<<

Visual Enterprise ™ ™

Language Reference

P46-0201-00

Copyright © 1999–2000 Cincom Systems, Inc. All rights reserved. Copyright © 1999–2000 Seagull Systems, Inc. All rights reserved. This product contains copyrighted third-party software.

Part Number: P46-0201-00 Software Release 3.2 This document is subject to change without notice. RESTRICTED RIGHTS LEGEND: Use, duplication, or disclosure by the Government is subject to restrictions as set forth in subparagraph (c)(1)(ii) of the Rights in Technical Data and Computer Software clause at DFARS 252.227-7013.

Trademark acknowledgments: CINCOM, CINCOM SYSTEMS, and the Cincom logo are registered trademarks of Cincom Systems, Inc. Visual Smalltalk is a trademark of Cincom Systems, Inc., its subsidiaries, or successors and are registered in the and other countries. Windows is a registered trademark of Microsoft, Inc. Win32 is a trademark of Microsoft, Inc. OS/2 is a registered trademark of IBM Corporation. Other product names mentioned herein are used for identification purposes only, and may be trademarks of their respective companies.

The following copyright notices apply to software that accompanies this documentation: Visual Smalltalk is furnished under a license and may not be used, copied, disclosed, and/or distributed except in accordance with the terms of said license. No class names, hierarchies, or protocols may be copied for implementation in other systems. This manual set and online system documentation copyright © 1999–2000 by Cincom Systems, Inc. All rights reserved. No part of it may be copied, photocopied, reproduced, translated, or reduced to any electronic medium or machine-readable form without prior written consent from Cincom.

Cincom Systems, Inc. 55 Merchant Street Cincinnati, Ohio 45246

Phone: (513) 612-2300 Fax: (513) 612-2000 World Wide Web: http://www.cincom.com Contents

Preface ...... xv About This Manual ...... xv Notation Conventions ...... xvii

Chapter 1 The Smalltalk Language Overview ...... 19 Language Changes ...... 19 Identifiers ...... 20 Literals ...... 20 Variables ...... 26 Variable Shadowing ...... 30 Pseudovariables ...... 31 Messages ...... 31 Sequences of Messages ...... 35 Cascading Messages ...... 35 Parsing Expressions ...... 36 Method Syntax ...... 37 Message Pattern ...... 37 Comments ...... 38 Assigning Values to Variables ...... 38 Returning Values ...... 39 Blocks ...... 39 Control Structures ...... 40 Conditional Execution ...... 41 Iterative Execution ...... 41 Boolean Evaluation ...... 42 Evaluating Blocks ...... 42 Language Upgrade Support ...... 43 Compiler Options ...... 43 Conversion Tools ...... 45

Chapter 2 Basic Building Blocks Overview ...... 47 Object Class ...... 48 Creating and Destroying Instances ...... 48 Accessing Instances ...... 49 Equality and Identity ...... 49 Hash Values ...... 50

Visual Smalltalk Enterprise Language Reference iii Contents

Testing ...... 50 Copying ...... 51 Evaluating Messages ...... 51 Events ...... 52 Reporting Exceptions ...... 57 Object Descriptions ...... 57 Object Finalization ...... 58 Boolean Classes ...... 59 Boolean Expressions ...... 59 Magnitude Classes ...... 60 Magnitude ...... 61 Character ...... 62 Date, Time and TimeStamp ...... 65 Numbers ...... 67 Float ...... 70 Fraction ...... 71 Integer ...... 71 Collection Classes ...... 72 Attributes of the Collection Class ...... 73 Enumerating Collections ...... 74 Converting Collections ...... 76 Creating Instances ...... 76 Common Protocol ...... 77 Class Bag ...... 78 Class HashedCollection ...... 78 Class Set ...... 79 Class Dictionary ...... 79 Class IdentityDictionary ...... 79 Class IndexedCollection ...... 79 Class FixedSizeCollection ...... 80 Class OrderedCollection ...... 81 Class SortedCollection ...... 82 Stream Classes ...... 82 Accessing Protocol ...... 84 Positioning and Reading Protocol ...... 84 Writing Protocol ...... 86 File System Interface Classes ...... 87 Files ...... 87 Opening and Accessing Files ...... 88 Directories ...... 89 File Association ...... 89 Pattern ...... 91 PropertyManager ...... 92 Accessing Properties ...... 93

iv Visual Smalltalk Enterprise Language Reference Chapter 3 The Graphics Model Overview ...... 95 The Coordinate System ...... 96 Coordinate System Independence ...... 97 Setting Graphics Display Units ...... 97 Graphic Classes ...... 98 Point ...... 98 Rectangle ...... 101 GraphicsMedium Classes ...... 103 GraphicsMedium ...... 104 Bitmap ...... 104 StoredPicture ...... 106 Printer ...... 107 Screen ...... 108 Window ...... 109 Graphics Tool Classes ...... 109 GraphicsTool ...... 109 TextTool ...... 112 Pen ...... 113 RecordingPen ...... 114 Font ...... 115 Colors ...... 116 Red, Green and Blue ...... 116 Cyan, Magenta and Yellow ...... 117 Grayscale ...... 118 The Color Class Hierarchy ...... 118

Chapter 4 Building a Graphical User Interface Overview ...... 121 Window and Panes ...... 122 Top Panes ...... 122 Subpanes ...... 122 Sizing and Positioning Panes ...... 123 Navigating Between Panes ...... 128 Controls ...... 130 Common Controls ...... 131 Windows 95 Controls ...... 135 OS/2 CUA Controls ...... 146 Dialogs ...... 151 Common System Dialogs ...... 151 Message Box ...... 152 Prompter ...... 153 Modal and Modeless Dialogs ...... 153 Building Dialog Boxes in Smalltalk ...... 154 Using a Resource Dialog Box in Smalltalk ...... 154

Visual Smalltalk Enterprise Language Reference v Contents

MenuWindow ...... 156 Keyboard Mnemonics ...... 156 Cursor Control ...... 157 Hide and Display Cursor ...... 157 Cursor Shapes ...... 157 Window Properties ...... 158

Chapter 5 ApplicationCoordinators Overview ...... 161 Models and Views ...... 161 Coordinating Views and Models ...... 163 Building a View Manager Application ...... 164 Building an Application Coordinator Application ....170

Chapter 6 Drag/Drop Overview ...... 175 User Interface ...... 175 Programming Interface ...... 176 DragDropObject ...... 177 DragDropObject Messages ...... 177 DragDropSession ...... 179 DragDropSession Messages ...... 179 Source and Target Panes ...... 181 Enabling and Disabling Drag/Drop ...... 181 Configuring Events ...... 181 Drag/Drop Messages ...... 183 Examples ...... 184

Chapter 7 Handling Exceptions Overview ...... 185 Ensured Execution ...... 185 Ensuring Execution Always ...... 186 Ensuring Execution Under Exceptional Circumstances ...... 188 Nesting Protection Blocks ...... 189 Exception Handling ...... 189 The Exception Hierarchy ...... 190 Handling Exceptions ...... 191 Signaling Exceptions ...... 193 Exception Sets and Filters ...... 193 Resumable and Nonresumable Exceptions ...... 194 The Exception Environment ...... 197 Exiting Handlers Explicitly ...... 199 Translating Exceptions ...... 202

vi Visual Smalltalk Enterprise Language Reference Chapter 8 Help Manager User Interface ...... 203 Programming Interface ...... 204 Adding Help To an Application ...... 204 OS/2 Dialog Windows ...... 205 Responding to User Requests ...... 207

Chapter 9 Smalltalk Link Libraries Overview ...... 209 Cross Platform Portability ...... 209 Accessing Smalltalk Link Libraries ...... 210 Statically Binding a Smalltalk Link Library ...... 211 Binding Smalltalk Link Libraries at Startup ...... 211 Dynamically Binding and Unbinding a Smalltalk Link Library ...... 212 Unbinding and Reclaiming Memory ...... 212 Smalltalk Library Logical Names and Map Files ...... 214 SmalltalkLibraryBinder Public Protocol ...... 215 Smalltalk Library Builder ...... 216 Using Smalltalk Library Builder ...... 216 Building Smalltalk Libraries ...... 217 Smalltalk Library Builder Options ...... 218 SmalltalkLibraryBuilder Public Protocol ...... 220 Smalltalk Library Bind/UnBind Events ...... 223

Chapter 10 Object Filer Overview ...... 225 The Object Filer and Smalltalk Libraries ...... 226 Installing the Object Filer ...... 226 Storing Objects ...... 227 Loading Objects ...... 227 Using the Clipboard ...... 228 Resolving Class Definition Changes ...... 228 Missing Classes ...... 229 Modified Classes ...... 229 Pre-specifying Class Definition Changes ...... 231 Describing Stored Objects ...... 235 Summaries ...... 235 Detailed Reports ...... 236 Customizing the Object Filer ...... 236 Dump Preprocessing and Load Activation ...... 236 Providing Your Own Message Handler ...... 240 Automatic Smalltalk Library Binding ...... 241

Visual Smalltalk Enterprise Language Reference vii Contents

Chapter 11 Workbench Link Protocol Overview ...... 243 Link Basics ...... 243 Defining Links ...... 244 Traversing Links ...... 245 Link Message Interface ...... 246 Object Messages ...... 246 PARTSEditor Messages ...... 246 PARTSLink Messages ...... 247

Chapter 12 The Parts Workbench Code Generator Overview ...... 249 Saving a Part as Smalltalk Code ...... 249 Loading a Part from a CLS File ...... 250 Loading a Part CLS file as Smalltalk Code ...... 250 Enabling Code Generation for a Class ...... 250 Adding Attribute Messages ...... 251 Changing the Creation Message ...... 252 Inheriting Code Generation Behavior ...... 253 Upgrading Generator Support ...... 253

Chapter 13 Dynamic Data Exchange (DDE) Overview ...... 255 Installing DDE Support ...... 255 DynamicDataExchange Class ...... 255 DDEClient Class ...... 256 Establish Hot Link with an Item on the Server ...... 256 Establish a Warm Link with an Item on the Server ...257 Request an Item from the Server ...... 257 Execute Commands on the Server ...... 258 Submit an Item to the Server ...... 258 Terminate a Hot Link ...... 258 Terminate a Warm Link ...... 259 Terminate a DDE Conversation ...... 259 DDEServer Class ...... 259 Export an Item ...... 260 Update an Exported Item ...... 260 Remove an Exported Item ...... 260 Terminate a DDE Conversation ...... 260 Server Object Messages ...... 261 Dynamically Export an Item ...... 261 Dynamically Change an Item ...... 261 Execute a Command ...... 262 DDE Examples ...... 262 Sample Client/Server Application ...... 262 Smalltalk Emuator Server ...... 264 viii Visual Smalltalk Enterprise Language Reference Chapter 14 Multiprocessing Classes Overview ...... 267 Process ...... 268 Priorities ...... 268 Process States ...... 269 The User Interface Process ...... 271 Semaphore ...... 272

Chapter 15 Client/Server Support Overview ...... 275 Asynchronous Communications ...... 275 Console Application Support ...... 276 Starting a GUI-less Development Session ...... 276 Console Support ...... 277 Developing a GUI-less Application ...... 278 Capturing Windows Messages ...... 279 TCP/IP Support ...... 280 TCP/IP Support Classes ...... 280 A Finger Client ...... 283 Socket Streams ...... 285 Error Handling ...... 285 Berkeley Data Structures ...... 286 Socket Functions ...... 286 Asynchronous Sockets ...... 287 Socket ...... 287 Writing Asynchronous Applications ...... 288 A Client ...... 288 Your Fortune Told Here ...... 290 Channels ...... 294 Sockets and Parts ...... 298 VisualWorks Compatibility Suite ...... 302 How To Implement A Client ...... 303 How To Implement A Server ...... 303 How To Use Datagram Sockets ...... 304

Chapter 16 System Classes Overview ...... 307 NotificationManager ...... 308 SystemDictionary ...... 309 ClassReader ...... 310 CompiledMethod ...... 311 Message ...... 312 Behavior ...... 312 Event Manager ...... 312 Managing Event Tables ...... 313

Visual Smalltalk Enterprise Language Reference ix Contents

SessionModel ...... 314 ServiceRegistry ...... 315 ClipboardManager ...... 315 Object Finalization ...... 316 What Finalization Does ...... 316 Basic Finalization ...... 317 SystemWeakRegistries ...... 319 Finalization in ExternalAddresses ...... 320 WeakRegistry ...... 321 WeakKeyedRegistry ...... 322 Weak Pointers ...... 323 Smalltalk Extensions for Weak Pointers ...... 324

Chapter 17 National Language Support Overview ...... 325 Host System Dependencies ...... 326 Developing a Multinational Application ...... 327 Separating Text Strings From Application Code ...... 328 The NLS Application Development Process ...... 329 Managing Text Strings During Development ...... 331 Managing Text Strings as Compiled Resources ...... 333 Accessing System NLS Settings ...... 335 Culture-Dependent Formatting ...... 335 Text Comparison, Sorting, and Casing ...... 335 Character and String Support ...... 336 Characters ...... 336 Strings ...... 337 Symbols ...... 340 FileStreams ...... 341 FileStreams with Double-Byte Characters ...... 341 Binary File Streams ...... 342 Supporting Text in Multiple Languages ...... 343

Chapter 18 Performance Profiler Overview ...... 345 How to Use the Profiler ...... 346 User Interface ...... 347 Report ...... 348 Programming Interface ...... 352

Chapter 19 OS Interface and API Calls Overview ...... 355 API Interface Classes ...... 355 Common Interface ...... 355 Windows Specific Interface ...... 356 OS/2 Specific Interface ...... 357 x Visual Smalltalk Enterprise Language Reference Dynamic Link Libraries and API Calls ...... 358 Making API Calls ...... 358 Passing Arguments in API Calls ...... 359 API Methods ...... 359 Adding API Calls ...... 362 CallBack ...... 362 Installing the CallBack Example ...... 362 Creating a CallBack ...... 362 ExternalBuffer and its Subclasses ...... 364 ExternalBuffer Subclasses ...... 365 Adding an ExternalBuffer Subclass ...... 365 ExternalBuffer Messages ...... 366 ExternalLong ...... 367 ExternalAddress ...... 367 ExternalSegmentedAddress ...... 368 Remote ExternalBuffers ...... 369 SelfDefinedStructure ...... 370 Resources ...... 373 Bitmap ...... 373 Icon ...... 373 Windows Memory Handles ...... 374 SelfInitializingObject ...... 375 Thread Support ...... 376 Making an API Call ...... 376 Return Values ...... 378 Configuring Stack Size ...... 378 Using Non-Smalltalk Memory ...... 378 Error Checking ...... 378 Calling Conventions ...... 378 Microsoft Windows Message Processing ...... 379 Windows Subclassing ...... 380 Windows Message Polling ...... 380 Interrupts ...... 381 OS/2 Message Processing ...... 382 WinSubclassWindow ...... 383 Creating Windows ...... 384 Primitive Methods ...... 384 Primitive Failure Handling ...... 385 User-Defined Primitive Methods ...... 386 Object Pointers ...... 386 Accessing Objects within Primitives ...... 387 Returning from a User Primitive ...... 387 Generating Smalltalk Interrupts within Primitives ....388 Memory Access and User Primitives ...... 388 Macros and Functions ...... 388 Protection Violation Handling ...... 390 Visual Smalltalk Enterprise Language Reference xi Contents

Chapter 20 OLE Support Overview ...... 391 OLE Applications ...... 391 OLE Container Support ...... 392 Structure of a Container Application ...... 392 The Container Application Framework ...... 393 Building a Container Application ...... 394 OLE Control Support ...... 396 Using OLE Controls ...... 396 OLE Client Site Object Interfaces ...... 398 OLE Container Object Interfaces ...... 399 Creating an OLE Application ...... 400 Acquiring OLE Objects ...... 400 Basic OLE Interface Support ...... 401 Acquiring OLE Interfaces ...... 401 Managing Object References ...... 402 Using OLE Interface Functions ...... 405 Error Handling ...... 405 Managing Memory ...... 406 Implementing OLE Objects ...... 407 Supporting OLE Interfaces ...... 407 Reusing OLE Objects ...... 409 Configuring Interface Function Processing ...... 410 Implementing Interface Functions ...... 413 Releasing an OLE Object ...... 414 Returning Values from an Interface Function ...... 415 Implementing ...... 416 ...... 418 COM Infrastructure Support ...... 419 Basic OLE Data Types ...... 419 OLE Enumerators ...... 420 OLE Monikers ...... 420 OLE Structured Storage Support ...... 421 OLE Uniform Data Transfer Support ...... 422 OLE Automation ...... 426 Using OLE Automation Objects ...... 426 Implementing OLE Automation Objects ...... 427 OLE Event Support ...... 427 OLE Support Framework ...... 428 OLE Pools ...... 428 OLE Data Structures ...... 429 OLE Function Binding Classes ...... 429

xii Visual Smalltalk Enterprise Language Reference Chapter 21 SOM Support Overview ...... 431 Installing SOM Support ...... 431 Running the SOM Demo ...... 432 SOM DLL Access ...... 432 SOM Proxy Base Classes ...... 432 SOM API Conventions ...... 433 Type Mappings ...... 434 Using SOM Objects in Smalltalk ...... 435 SOM Initialization ...... 435 Create Proxy Class ...... 435 Create Proxy Methods ...... 435 Inheritance ...... 436 Memory Management ...... 436 Implementing SOM Methods in Smalltalk ...... 437

Chapter 22 Multiple Document Interface (MDI) Overview ...... 439 Installing MDI Classes ...... 439 Delivering an MDI Application ...... 439 Activating MDI Mode ...... 440 Programming Interface ...... 442 Creating an MDIFrame Window ...... 442 Creating an MDIChild ...... 443 MDIFrame Class ...... 444 MDIViewManager Class ...... 446 MDIMenu Class ...... 447 MDISystem and MDITranscript Classes ...... 449

Chapter 23 Microsoft Windows Interfaces Overview ...... 451 Registration Database ...... 451 Using the Registration Database ...... 452 Messaging API (MAPI) ...... 453 Installing MAPI Support ...... 453 Using MAPI Services ...... 453 MAPI Support Classes ...... 455 Multi-Media API ...... 456 Plug-and-Play Awareness ...... 457

Appendix A Visual Smalltalk Syntax Summary ...... 459 How Syntax is Specified ...... 459 Smalltalk Syntax ...... 460

Visual Smalltalk Enterprise Language Reference xiii Contents

Appendix B Programming Guidelines ...... 465 Introduction ...... 465 Style Guidelines ...... 466 Methods ...... 466 Variable Names ...... 468 Capitalization ...... 468 Blank Lines ...... 469 Brackets and Parentheses ...... 469 Formatting and Indentation ...... 471 Comments ...... 472 Coding Guidelines ...... 473 Class methods ...... 473 Modifying Existing System Methods ...... 475 Extending System Classes ...... 475 Variable Usage ...... 476 Nested Conditionals ...... 482 Explicit Class References ...... 485 Class Type Checking ...... 486 Initialization ...... 488 Inappropriate Array Usage ...... 490 Hide Implementation Details ...... 491 Implementing ‘Equals’ ...... 493 Testing for nil ...... 495

Appendix C Error Messages ...... 497 Introduction ...... 497 Virtual Machine Errors ...... 498 Internal Exceptions ...... 498 Low System Memory ...... 499 Corrupted Image ...... 500 Compiler Error Messages ...... 501 Compiler Warning Messages ...... 508

Appendix Implementation Limits ...... 509 Open-coded Blocks ...... 509 Browser Visibility ...... 510 Performance ...... 510 Non-overridable Methods ...... 510 Special Treatment Only at Compile Time ...... 511 Special Treatment at Compile Time and Translation Time ...... 512

Index ...... 515

xiv Visual Smalltalk Enterprise Language Reference Preface

Visual Smalltalk and Visual Smalltalk Enterprise are 32-bit development environments that allows you to write and run 32-bit applications under Microsoft Windows 95, Windows 3.1, Windows NT, and IBM OS/2 Warp. This product is a 100% pure object- oriented development environment that frees developers from worry about many low-level details. It provides significant productivity gains over non-object-oriented and hybrid development tools. The books included with Visual Smalltalk (we will frequently use the shorter name to refer to both products) offer a wealth of information for both new and experienced Smalltalk programmers. About This Manual This manual is organized into the following chapters: • Chapter 1, The Smalltalk Language, discusses the main ideas underlying object-oriented programming and explains Smalltalk syntax. • Chapter 2, Basic Building Blocks, provides an overview of many the most fundamental elements used to build Visual Smalltalk applications. • Chapter 3, The Graphics Model, describes the graphics interface classes you use to draw shapes in a window. • Chapter 4, Building a Graphical User Interface, describes the Window classes and panes used to construct a user interface, and how to build the interface in an application framework. • Chapter 5, Application Coordinators, describes the special classes that help you build a complete application. • Chapter 6, Drag/Drop, describes the classes and methods that allow you to incorporate drag/drop functionality into your applications.

Visual Smalltalk Enterprise Language Reference xv • Chapter 7, Handling Exceptions, describes the mechanisms behind ensured execution, and the mechanisms available to handle exceptions. • Chapter 8, Help Manager, describes how to access and use the system Help facility from a Visual Smalltalk application. • Chapter 9, Smalltalk Link Libraries , describes how to use and build libraries of Smalltalk objects. • Chapter 10, Object Files, describes how to use the Object Filer. • Chapter 11, Workbench Link Protocol, describes how links in the workbench can be used in Smalltalk. • Chapter 12, The Parts Workbench Code Generator, describes how to design parts for conversion to Smalltalk code, and the code produced from parts. • Chapter 13, Dynamic Data Exchange (DDE), describes the classes and methods that allow you to create DDE client/server applications. • Chapter 14, Multiprocessing Classes, explains the mechanisms available to simulate multiprocessing. • Chapter 15, Client/Server Support, describes the support for TCP/IP and GUI-less application development. • Chapter 16, System Classes, discusses the classes that dispatch events to windows, maintain the Smalltalk name space, and support compiling and maintaining Smalltalk code. • Chapter 17, National Language Support (NLS), shows you how to create applications that can be used internationally without changing the source code. • Chapter 18, Performance Profiler, shows you how to use the Visual Smalltalk Performance Profiler to fine-tune your applications. • Chapter 19, OS Interface and API Calls, describes the classes and methods that access operating system services. • Chapter 20, OLE Support, describes how to use the services of OLE in a Smalltalk application. • Chapter 21, SOM Support, describes how to use the services of SOM in a Smalltalk application. • Chapter 22, Multiple Document Interface (MDI), shows you how to use the classes and methods that allow you to apply this interface standard.

xvi Visual Smalltalk Enterprise Language Reference About This Manual

• Chapter 23, Microsoft Windows Interfaces, describes how to install and use the Smalltalk classes that interfaces with the Microsoft Windows registration database, MAPI, and similar services. • Appendix A, Smalltalk Syntax Summary, provides Smalltalk syntax rules in an extended BNF format. • Appendix B, Programming Guidelines, shows you how you can make your code more readable, maintainable, and portable. • Appendix C, Error Messages, describes the error messages you may receive from either the virtual machine or the compiler, including the probable causes and actions that you can take to resolve the problem. Notation Conventions We use some standard notation conventions in this book to help you understand what you are reading: • Proper names of actual classes, variables, methods, instances, and other Smalltalk structures are printed in boldface, with appropriate capitalization as required. For example, contrast “class Dictionary” with “a dictionary class.” • Examples of Smalltalk code are printed in boldface in the standard font. Spaces may be inserted between arguments for easier reading, though they are not necessary. Long and complex (nested) expressions, such as loops, are broken into separate lines and indented one tab per nesting level, for example: [i<10] whileTrue: [ sum := sum + (a at: i). i := i + 1]. • The notation AClass class>>aMethod refers to the class method aMethod in the class AClass. The notation AClass>>aMethod refers to the instance method aMethod in the class AClass. The notation message[...] refers to a message and its optional arguments. • New terms appear in italics the first time they are used, usually when the term is first defined. Additional information about these terms can be found in the Glossary.

Visual Smalltalk Enterprise Language Reference xvii • Placeholder names that are meant to be replaced with actual names appear in italics. For example, in the following expression, you replace filename.st with an actual filename: (File pathNameReadOnly: 'filename.st') fileIn; close. • File names and pathnames are printed in uppercase. For example: TUTORIAL\PARTS\PHONE.PAR When a release number is part of the filename, the release number is represented by nnp. For example: VRESnnp.SLL where: nn is the version number p is the platform (W = Windows, O = OS/2) • Menu names and menu items are printed in italics and are separated by a slash when both appear together. For example, File/Save As... refers to selecting the Save As... menu item from the File menu. • When used with a pair of keycap names, the plus sign indicates that you press and hold the first while pressing the second. For example, Alt + O indicates that you press and hold the Alt key while you press the O key, then release both. • Left/right mouse button orientation is configurable using the operating system control panel. To avoid having to note this fact constantly, we assume the left mouse button is the normal selection button. If your system is configured differently, please make allowance for this fact in reading instructions.

xviii Visual Smalltalk Enterprise Language Reference CHAPTER The Smalltalk 1 Language Overview The Visual Smalltalk Enterprise User’s Guide gives a general overview of the kinds of things Visual Smalltalk deals with, namely kinds of object, descriptions of objects, and how objects communicate. In this chapter we describe in more detail the Smalltalk language part of Visual Smalltalk—the vocabulary and construction rules used to form expressions. The discussion here will be informal. For a formal representation in the BNF meta-language, refer to appendix A. Language Changes Visual Smalltalk 3.1 implements a number of changes to the syntax and semantics of previous versions of Visual Smalltalk, for two primary reasons: • To improve language compatibility with Visual Works • In anticipation of the work being done by the X3J20 (ANSI) committee Where a change or addition has been made, the discussion is marked with the icon shown to the left. An effort has been made to include examples illustrating the new and old syntax. 3.1 The changes occur in the following areas: • Numeric expressions • Literal symbol names • Literal arrays containing literals • Literal byte arrays (new) • Block arguments and temporaries • Variable shadowing A few compiler options and tools are provided to help you upgrade existing applictation code to use these changes. These are briefly described at the end of this chapter. For details about compatibility between Visual Smalltalk and Visual Works, refer to the Compatibility Guide document.

Visual Smalltalk Enterprise Language Reference 19 CHAPTER 1 The Smalltalk Language Identifiers When we refer to objects, as we must in sending messages, we generally refer to them by their names, or identifiers. Identifiers are either constants or variables. Identifiers are made up of a sequence of letters and digits, and may include the underscore character (_). An identifier must begin with either a letter or the underscore.

Literals A literal is a Smalltalk expression that always refers to the same object. Unlike variables, the referent of a literal cannot change. Several objects in Smalltalk have literal names, including numbers, characters, strings, symbols, arrays, and a few special literals.

20 Visual Smalltalk Enterprise Language Reference Identifiers

Numbers Numbers are objects of class Float, Integer, Fraction, and FixedPoint. If a number contains a decimal point, it is an object of class Float or FixedPoint. A number consisting only of digits, and possibly a leading minus sign, is an Integer.

Integers are named by their numeral representation, with or without a minus sign; so ..., “-3,” “-2,” “-1,” “0,” “1,” “2,” “3,” ... are names for the integers ..., negative three, negative two, negative one, zero, one, two, three, ... .

Visual Smalltalk Enterprise Language Reference 21 CHAPTER 1 The Smalltalk Language

A Fraction is a ratio of two numbers, its numerator and denominator. If either the numerator or denominator is a Float, the fraction evaluates to a Float. A FixedPoint, or scaled, number has a fixed set of decimal places, with the number of places specified following an s. For example, 3.5s2 evaluates to 3.50. A trailing s is displayed (3.50s), 3.1 indicating that it is a fixed point value. If a numeric expression includes r, the integer preceding r define the radix, or base, for the number following the r. The radix is always given in base 10. Uppercase letters A to Z are used to represent integer values 10 and higher when the radix is greater than 10. For example, hexadecimal numbers begin 16r, followed by their hexadecimal representation. To express a negative value for number with a radix, the minus sign must precede the radix integer (for example, -16r3F). If the number includes e, d, or q, the number is in exponential 3.1 notation. The digits following the indicator letter are the exponent. All three exponential forms evaluate to the precision of Float (double precision). Examples of number constants are: 15 3.1416 -100.125 16rFF -16rFF (old syntax: 16r-FF) l.0e-3 3.5s2 Characters Characters have literal names, consisting of the character itself. To make sure the character is taken as itself, it is prefixed with a dollar sign ($). $A means the character uppercase A.

Any printing character can be represented in this way: $a, $@, $7, $$.

22 Visual Smalltalk Enterprise Language Reference Identifiers

Other characters can be represented by appropriate Smalltalk expressions, for example to identify a character by ASCII value: Character value: anInteger Strings A string consists of a sequence of one or more characters. To write a string in Visual Smalltalk, enclose the characters in single quotation marks, such as 'abc 123'. The string can contain any characters. Because single quotes are string delimiters, to include a single quote in a string it must be doubled: 'You can''t do that.'

Visual Smalltalk Enterprise Language Reference 23 CHAPTER 1 The Smalltalk Language

Symbols Symbols are, like strings, sequences of characters, but are unique. That is, two references to symbols consisting of the same sequence of characters refer to the same symbol.

A symbol literal is formed by prefixing # to the symbol. A symbol may now contain any character, including spaces. To form a literal for a symbol, enclose the symbol in single quotation marks, like a string. 3.1

Examples of symbol literals are: #July, #at:put:, #Fraction, #'this is a symbol'. Arrays An array is a kind of collection. When represented by a constant, the elements of the array are enclosed in parentheses, and the array is preceded with a #. Literals within a literal array must also be prefixed with #. This is a change from previous versions Visual Smalltalk that requires updating code written under earlier versions of Visual Smalltalk. 3.1

24 Visual Smalltalk Enterprise Language Reference Identifiers

( )

Examples of arrays are: #(1 2 3) #( #June #July #August) old syntax: #( June July August) #('yes' 'no' 'maybe') Byte Array Literals A byte array is an array object containing “bytes,” small integers in the range 0 to 255. You can create a literal byte array with an expression that starts 3.1 with the characters “#[” and ends with “]”. Between the brackets there may be any number of integers in the range 0 to 255 (decimal), separated by spaces. For example: #[ 115 24 254 ] Special Literals There are three special literals: nil, true, and false. • nil is the only instance of the class UndefinedObject. nil is the default value for any new object name until a specific value is assigned to it. • true and false are Boolean objects.

Visual Smalltalk Enterprise Language Reference 25 CHAPTER 1 The Smalltalk Language

Variables A variable name changes its referent, or value. The value is assigned to the variable when needed, so that the object can be referred to using the variable name. The object referred to can change over time, while the program runs, hence the name “variable.”

The formation rules for identifiers were stated earlier. There are Smalltalk conventions that some variable types begin with a lowercase letter and others variable types begin with an uppercase letter. This convention was enforced in previous versions of Visual Smalltalk, but is no longer required. Following 3.1 the convention, though no longer enforced, is still encouraged. For example, by convention global variables begin with an uppercase letter, and temporary variables begin with a lowercase letter. The convention for each type is noted below. It is somewhat unusual to begin a variable name with an underscore character in Smalltalk, and should be reserved for special purposes only. Smalltalk uses seven kinds of variable, as summarized in the following table. Table 1-1: Visual Smalltalk variable types.

Variable type Where defined How Used Instance Class definition Store value defining an instance’s state Class Class definition Store value defining a class’s state Class instance Class class definition Store value defining a class’s state

Temporary In a method Store a value for use within a method Pool Class definition Store a value to be used by several classes Global Anywhere Store a value accessible by the whole Visual Smalltalk system.

26 Visual Smalltalk Enterprise Language Reference Identifiers

Instance Variables Instance variables are created specifically for the use of an instance of an object. They are used to hold information specifically about that instance. Instance variables are declared in the class definition, and a new instance of the variable is created for each new instance of the class. Two instances of the same class will each have instance variables with the same name, but the variables themselves will be distinct and can hold different values. Instance variables are inherited by subclasses of the defining class. The class definition can declare both named and indexed instance variables. Named instance variables are more common than indexed instance variables. Indexed variables can contain either a pointer or a byte value. If a class defines indexed variables with a pointer value, then the class can have named variables also; otherwise, only the indexed variables are permitted. Instance variables are accessible only to the instance methods of the class to which it belongs. Other methods and objects have no direct access to the variable. Instance variables are typically initialized when an instance is created, either in the new or new: method or in a subsequent initialize method. They exist as long as the instance exists. The number of indexed instance variables that an object has is determined when it is created, using the new: message with an integer argument. The number of instance variables can differ among instances of the same class. For example, #(1 2 3) and #('up' 'down') are both instances of class Array, but they have different numbers of indexed instance variables: three and two respectively. Many objects return the number of their indexed instance variables in response to the message size. Indexed instance variables are accessed and changed by sending messages, usually at: and at:put:, and specifying an integer index. By convention, instance variable names begin with a lowercase letter. Class Variables Class variables are variables whose names and values are shared by a class, its instances, its subclasses, and instances of the subclasses. Class variables are initialized to nil when a class is first

Visual Smalltalk Enterprise Language Reference 27 CHAPTER 1 The Smalltalk Language

defined. They are set to specific values when a message is explicitly sent to do so. They exist until the class is redefined to delete them. Both class and instance methods, of a class and of its subclasses, can refer to a class variable. By convention, class variable names begin with an uppercase letter. Class Instance Variables Class instance variables are similar to class variables, except that they are created for each subclass of the defining class. In this way it is an instance variable for classes treated as instances of their metaclass. When a class declares a class instance variable, a new variable is created for each subclass of that class. Each subclass then has its own instance of the variable and retains its own value for the variable, but each subclass has a variable with the same name. Each subclass can easily set the value using its own initialization methods, overriding values defined in a superclass. Class instance variables are defined in the class definition, just like class and instance variables. Using the Class Hierarchy Browser, select a class and click on the class radio button. The only variable category shown is the class instance variable list. Only class methods of a class and its subclasses can refer to a class instance variable; instance methods cannot. Subclasses inherit its name but not its value. Class instance variables are initialized to nil when a class is first defined, and can be set to specific values by sending assignment messages. Once defined, they exist until the class is redefined to delete them. By convention, class instance variable names begin with a lowercase letter. Global Variables Global variables are variables that are available to every object in Visual Smalltalk. They are used when an object needs to be made universally available. Global variables are used less frequently now than in earlier implementations of Smalltalk. It is preferable to use class or class instance variables when reference does not need to be global, as is usually the case.

28 Visual Smalltalk Enterprise Language Reference Identifiers

A new global is defined any time a value is assigned to a name beginning with an uppercase letter that is not already defined in Visual Smalltalk. A verification prompt is displayed before the variable is created. The global variable then continues to exist until it is explicitly deleted. There are several examples of global variables in Visual Smalltalk. Class names are global variables, allowing any object to refer to them. The name Smalltalk is also a global variable, referring to Visual Smalltalk itself as the instance of class SystemDictionary. Disk is a another global variable, which stores the current disk and directory path. To see a full list, enter “Smalltalk” in a workspace and inspect it. By convention, global variable names begin with an uppercase letter. Temporary Variables Temporary variables are used for temporarily storing an object within a method or a block. (Usage within blocks is described later, under “Blocks.”) Method temporaries are declared at the beginning of the method, placed between vertical bars: | george | Temporaries must be declared before they can be used. When declared, a temporary is initialized to nil each time the method is invoked. Temporary variables exist only during the execution life of the method or block. By convention, temporary variable names begin with a lowercase letter. Workspace Variables Workspace variables are temporary variables whose scope is restricted to a workspace. They are created when you assign a value to a previously undefined name in a workspace window. For example, if the following expression is evaluated in a workspace, it creates a new object and assigns it to a variable named george: george := Object new. The variable can be accessed and manipulated within this workspace, but not from anywhere else in the system.

Visual Smalltalk Enterprise Language Reference 29 CHAPTER 1 The Smalltalk Language

Workspace variables are useful for testing expressions that require a variable, without having to redeclare the variable with every evaluation. The variable continues to exist as long as the workspace remains open, unless you explicitly remove it. Note that this style of definition fails for the Transcript or any method definition, causing an undeclared variable compiler error. Also if you reference a variable name within a workspace before assigning it a value as shown above, an undeclared variable compiler error occurs. By convention, workspace variable names begin with a lowercase letter. Pools and Pool Variables Pool variables are declared and defined in dictionaries, called pools. A class gains access to these variables by naming the appropriate pool dictionary in its class definition. Pools are useful for providing access to variables to several classes that are not related by inheritance. For example, the pool ColorConstants defines a number of names for system colors. To use these variable names in a class, you include “ColorConstants” in the Pool Dictionaries section of the class definition. You can then refer to the system colors by the names in the dictionary. For more information on defining the dictionary, see the description of dictionaries later in this manual. Pool variables exist until they are no longer referenced by either the pool dictionary that contains them or any methods in any classes. By convention, pool and pool variable names begin with an uppercase letter. Variable Shadowing In some situations it is useful to be able to reuse a variable name that has already been declared in a containing, or outer scope. In previous versions of Visual Smalltalk, declaring a variable that has already been defined has been treated as an error. You could 3.1 assign a new value to the variable, but not create a new variable with the same name. Variables in an inner scope are now allowed to have the same names as those in an outer scope.

30 Visual Smalltalk Enterprise Language Reference Messages

The variable with the smallest enclosing scope to the variable reference is the variable that is accessed. The name scopes associated with a variable, from outer to inner, are in order: 1. globals 2. instance variables 3. method arguments and temporaries 4. block arguments and temporaries Workspace variables have the same scope as method temporaries within the workspace. If the compiler option #warnQuestionable is set, the system will generate a warning if an inner variable has the same name as an outer variable. Note that while variable shadowing is allowed, it is not encouraged. Code that does not use variable shadowing is easier to understand, and so is easier to maintain. Pseudovariables Two pseudovariables, self and super, depend on their context for their reference. self refers to the receiver of the message. It is usually used within a method to send additional messages to the receiver. super refers to the superclass of the class that defines the message sent to the receiver. It causes the search for a method to start one level up the hierarchy. Instead of looking for the method in the class of the receiver, super starts method lookup in the superclass of the defining class. You cannot reassign the values of the pseudovariables. Messages The three kinds of messages are unary, binary, and keyword. Each kind of message requires a message selector. Binary and keyword messages also take one or more arguments. Unary messages take no arguments.

Visual Smalltalk Enterprise Language Reference 31 CHAPTER 1 The Smalltalk Language

For example:

Expression Meaning

2 sqrt Two, compute your square root and return its value. $A class $A, what class are you an instance of? aTextPane contents aTextPane, tell me what text you contain.

#(a b c) size What is the size of this array?

Binary messages use a binary selector and take one argument.

32 Visual Smalltalk Enterprise Language Reference Messages

Binary selectors can be a minus sign, a binary selector character, a minus sign followed by binary selector character, or two binary selector characters. Examples of binary messages are shown in the following table:

Expression Meaning

3 + 4 Send the message + to 3 with argument 4, meaning: 3, add 4 to yourself and answer the result.

2 * 3 Send the message * to 2 with argument 3, meaning: 2, multiply yourself by 3 and answer the result. 500 @ 225 Send the message @ to 500 with argument 225, creating a point. The receiver becomes the x coordinate, and the argument becomes the y coordinate.

'Four score and ' ,'seven years Send the comma message to a string with another string ago' as argument, returning the concatenation of both strings. a <= b Send to a the message “less than or equals” with the argument b. This message returns either true or false.

Keyword messages are composed of any number of words, each followed by a colon; it takes as many arguments as it has keywords.

Visual Smalltalk Enterprise Language Reference 33 CHAPTER 1 The Smalltalk Language

34 Visual Smalltalk Enterprise Language Reference Messages

For example:

Expression Meaning anArray The keyword message puts the at:put: specified string, at: 1 'Alice', at the specified index, 1. put: 'Alice' Point x: 55 y: 200 Point, create an instance of yourself whose x coordinate is at 55 and whose y coordinate is at 200. Date The keyword message newDay:month:year: makes an newDay: 15 instance of class Date. month: #July year: 93

In Smalltalk, all message selectors begin with a lowercase letter. Each expression in Smalltalk returns a single object as its result. The expression can also assign its result to a variable. Sequences of Messages You can send several messages in sequence if each message ends with a period ( . ). For example: | aVariable anotherVariable | aVariable := 3. anotherVariable := 5. aVariable + anotherVariable. Cascading Messages You can send a series of messages to a single receiver without repeating the receiver’s name each time. This is referred to as cascading.

To cascade messages, end the first message with a semicolon, then, without repeating the receiver’s name, put the next message selector and parameters. Repeat this, ending each selector/ parameter group with a semicolon, until you are done sending

Visual Smalltalk Enterprise Language Reference 35 CHAPTER 1 The Smalltalk Language

messages to this receiver. Terminate the cascade with a period. For example, you can use cascading to set a number of properties for an object: | aBall | aBall := Ball new . aBall size: 5; color: clrRed; weight: 1.5 . For the last three lines the receiver is aBall. The messages to set the receiver’s size, color and weight are all sent to the same object, even though it is named only once. Parsing Expressions Smalltalk expressions are parsed from left to right, according to an order of precedence: 1. First, all unary messages are parsed, from left to right. 2. Next, all binary messages are parsed, from left to right. 3. Finally, all keyword messages are parsed, also from left to right.

In Smalltalk, x+y* z is equivalent to (x + y) * z, which is different from the standard mathematical order giving “*” a higher precedence than “+.” Unary messages take precedence over binary messages. That is, 1+2sqrt is equivalent to 1 + (2 sqrt). Binary messages take precedence over keyword messages, so: anArray at: 20 put: average + bias is the same as: anArray at: 20 put: (average + bias) where average and bias are variables. Keyword messages of more than one word, for example at:put:, are parsed as one message. Parentheses can be used to override the default parsing order. Expressions within parentheses take precedence over expressions outside of parentheses.

36 Visual Smalltalk Enterprise Language Reference Method Syntax

Method Syntax A complete method includes a message pattern, a comment, temporary variable declarations, and a series of Smalltalk expressions. When you use a browser to create a method, it gives you a template to fill in: messagePattern "comment" | temporaries | statements Message Pattern The message pattern specifies how objects will send this message to execute the method. It includes the message selector and, if the selector takes one or more argument, identifiers used to refer to arguments within the method.

For example, the max: method for a magnitude takes a single argument. It’s message pattern is: max: aMagnitude The between:and: method takes two arguments: between: min and: max Values assigned to aMagnitude, min, and max are local to these methods, and are declared in the patterns.

Visual Smalltalk Enterprise Language Reference 37 CHAPTER 1 The Smalltalk Language

Comments A comment is a sequence of characters enclosed within double quotes. The Visual Smalltalk compiler ignores a comment anywhere except within a string.

Comments are commonly used in methods, especially at the beginning of a method, to describe what the method does. Further comments can be placed throughout the method to explain lines or sections in the code. Comments for methods that are not intended as part of the object’s public interface should begin with “Private-.” An example of a comment is: "Return the size of the receiver" Assigning Values to Variables Smalltalk assigns values to variables using the assignment operator, “:=.” A single value can be assigned to several variables by using several assignment operators.

For example: aNum := 2 + 3. aString := 'Hello, world!'. aDate := Date today. temp1 := temp2 := false.

38 Visual Smalltalk Enterprise Language Reference Method Syntax

Returning Values The return operator, “^,” returns the value of the expression.

For example, the expression: ^$a asUppercase returns $A. Method execution terminates at an expression preceded by the return operator. The method then returns the object computed by the expression. Blocks A block is a series of expressions, delimited by square brackets, grouped for deferred evaluation. A block is similar to a method, but used to control evaluation within a method. For example: [index := index + 1. anArray at: index put: 0] Blocks can have arguments, introduced by block argument variables, each preceded by a colon. The list of arguments is terminated by a vertical bar. Blocks can also have their own temporary variables, referred to as block temporary variables. This is a list of temporary variables following the block arument list, and is enclosed by vertical bars. 3.1 Following block arguments and temporaries is the sequence of messages.

|||

Visual Smalltalk Enterprise Language Reference 39 CHAPTER 1 The Smalltalk Language

The statements in a block may refer to its block arguments and block temporaries, the arguments and temporaries of any enclosing blocks, the arguments and method temporaries of the enclosing method, and variables visible to the method. Block arguments and temporaries are not accessible from outside the block. An example of a block with a single block argument is: [ :anArray | total + anArray size ] The value for the block argument may be provided by an interator or by sending it an value: message. In this example, total is probably a method temporary variable. The block in this sample method uses both a block argument and a block temporary: countMapping "Count the number of elements of myself that map into value1 or value3." | result | result := 0. self do: [ :anElement | | mappedElement| mappedElement := anElement mapping. (mappedElement = 'value1' or: [ mappedElement = 'value3']) ifTrue: [ result := result + 1]]. ^result The scope of a block includes: • its arguments • its temporaries • the temporary variables and arguments of the method and blocks in which it is defined • the instance variables of the object in whose class it is defined A block returns the value of the last expression evaluated. Control Structures Blocks are the basis for control structures in Smalltalk. Control structures are invoked by sending messages with blocks as arguments. Three basic forms, with several variations each, are defined in Visual Smalltalk. You can define additional forms using these predefined ones as building blocks.

40 Visual Smalltalk Enterprise Language Reference Control Structures

Conditional Execution The following predefined conditional execution messages are available: ifTrue: [trueBlock] ifFalse: [falseBlock] ifTrue: [trueBlock] ifFalse: [falseBlock] ifFalse: [falseBlock] ifTrue: [trueBlock] The receiver must be an expression that evaluates to true or false and the argument must be a block. An ifTrue: argument block is evaluated if and only if the receiver has the value true. An ifFalse: argument block is evaluated if and only if the receiver has the value false. The conditional messages return the last expression in the executed block, or nil if no block is executed.

NOTE: Subclasses should not override the messages described above.

Iterative Execution The following predefined iterative execution messages are available: whileTrue whileFalse whileTrue: [aBlock] whileFalse: [aBlock] The receiver of each of these messages must be a block. The message whileTrue causes the receiver to be executed until it returns false, and the message whileFalse causes the receiver to be executed until it returns true. The arguments to whileTrue: and whileFalse: must be blocks as well. The message whileTrue: works as follows: the receiver block is evaluated. If it returns true, the argument block is evaluated. The iteration continues until the first block evaluates to false. The message whileFalse: works in the corresponding but opposite fashion. Both whileTrue: and whileFalse: always return nil.

NOTE: Subclasses should not override the messages described above.

Visual Smalltalk Enterprise Language Reference 41 CHAPTER 1 The Smalltalk Language

Boolean Evaluation The Boolean operators and: and or: also take blocks for their arguments. The receiver of each of these messages must be an instance of a subclass of Boolean, and the block, if evaluated, must return either true or false. The message and: works as follows: if the receiver is true, the block is evaluated. The message returns the result of evaluating the last expression in the block. If the receiver of the and: message is false, the block is not evaluated and false is returned. The message or: works as follows: if the receiver a false, the block is evaluated. The message returns the result of evaluating the last expression in the block. If the receiver of the or: message is true, the block is not evaluated and true is returned. Evaluating Blocks Creating a block does not cause it to be executed. It is executed as a whole when the block is evaluated. A block is evaluated when it is sent the appropriate evaluation message. The message value is sent when the block has no arguments; the message value: is sent when the block has one argument; value:value: when it has two. For example, given the expression ba := [c := 3 + 4], the expression that sets c to 7 is evaluated when the expression below is executed: ba value The message value (or its variants) is not ordinarily sent directly by your application. Instead, it is sent as a result of the processing that begins when a method is executed. Because of this deferred evaluation, you can use blocks to select which of several sets of expressions get executed. For example: sum := ( anArray size = index ifTrue: [0] ifFalse: [1] ) Use blocks when you want to repeat sets of expressions, either conditionally or unconditionally. For example, the following expression repeats the expression in the block seven times unconditionally: result := 1. 7 timesRepeat: [result := result + 2.718]

42 Visual Smalltalk Enterprise Language Reference Language Upgrade Support

The following conditional expression sums all the elements of an array and increments the index while it is true that the index is not greater than the size of the array: sum := 0. index := 1. [index <= anArray size] whileTrue: [sum := sum + (anArray at: index). index := index + 1] A block can contain an expression preceded by the return operator (the caret ^). Evaluating such an expression causes execution to return from the method containing the block. The value returned from the method is the value returned from the block. For example: needToAdd: target "Add the target to the ordered collection. Return true if it wasn’t already added; return false if it was already added."

anOrderedCollection do: [:each | each = target ifTrue: [^false]]. anOrderedCollection add: target. ^true Blocks can be nested as deeply as required. Language Upgrade Support This section briefly describes compiler options are available to help you convert to the new language syntax and semantics, as well as a few tools to automate some of the required changes. Compiler Options To support applications developed using previous versions of Visual Smalltalk while you convert your applications to the new syntax, Visual Smalltalk implements a few compiler options allowing you to select a level of support for the old syntax.

Visual Smalltalk Enterprise Language Reference 43 CHAPTER 1 The Smalltalk Language

Option Default Description

#language #extended Specifies the level of language compatibility, based on the value passed to the compiler: #backwardCompatible use Visual Smalltalk 3.0 syntax and sematics. #X3J20 use X3J20 standard syntax only. #extended includes X3J20 support, further extensions (mainly for Visual Works compatibility), plus “bridge” extensions for backward compatibility. #warnQuestionable true Issues a warning if a block argument or temporary usage is questionable. #warnObsolete false Issues a warning of obsolete usages if #backwardCompatible option is set. For example, a warning is issued if you reference a block argument outside the block when it was not declared as a tempoarary variable for the method Important Note: The “bridge” extensions included in the #language #extended compiler option will be be supported in Visual Smalltalk and Visual Smalltalk Enterprise release 3.1 only. Future releases will not support these bridge extensions.

To set compiler options globally: • In Visual Smalltalk Enterprise, set the options using the compilation preferences dialog (Options / Preferences / Compilation). • In Visual Smalltalk, redefine the default options by editing the CompilerInterface setDefaultOptions class method and reinitializing the class. For example, to add the warnObsolete option, evaluate the following expressions in a workspace: aCompilerInterface := CompilerInterface new. aCompilerInterface addOption: #warnObsolete. CompilerInterface setDefaultOptionsFrom: aCompilerInterface.

44 Visual Smalltalk Enterprise Language Reference Language Upgrade Support

Conversion Tools To help you update your application code to the Visual Smalltalk 3.1 syntax and semantics, a few classes are provided in a Smalltalk library (VSAN31.SLL) containing methods to search for and optionally replace old syntax. The main class is SystemSanityCheck. To install the classes, select “System Sanity Check” in the Services Browser, and click Install. A workspace file, ANSI.WS, contains several scripts illustrating how to use the supplied classes to help automate updating your existing Smalltalk code. Comments in the workspace indicate what each script does. In general, the scripts evaluate your application code for compliance with 3.1 syntax, and optionally perform automated source corrections. Some updates can be performed automatically, such as correcting old style literal arrays. Other corrections, such as invalid block temporary variable usage, cannot be made automatically. Messages in the transcript indicate what corrections you need to make in your code. Browse the methods in the SystemSanityCheck class to create your own tools as well.

Visual Smalltalk Enterprise Language Reference 45

CHAPTER Basic Building 2 Blocks Overview This chapter describes fundamental classes and features that serve as basic building blocks for your applications: • Object Class Describes the class Object, the root of the class hierarchy, and covers some of the wide variety of default behavior it implements. • Boolean Class Describes the class Boolean, its subclasses True and False, and certain Boolean operators. • Magnitude Classes Explains how to compare objects that are subclasses of Magnitude. It also describes the classes that create instances of alphanumeric characters, various kinds of numbers, date, and time. • Collection Classes Explains how to enumerate the elements of a subclass of Collection, how to perform specified operations on each element, how to collect only those elements that meet a specified criterion, and how to convert one kind of collection into another. It describes attributes of collections, and then discusses several of the most useful subclasses. • Stream Classes Explains how to move through a stream, read it, and write to it. It then describes the classes ReadStream, WriteStream, and ReadWriteStream. • File System Interface Classes Describes the classes FileSystemEntity, File, Directory, and FileVolume, their general attributes, and how to manipulate file system interface objects. • Pattern Class Performs object pattern matching. • PropertyManager Describes how to define and use properties for objects.

Visual Smalltalk Enterprise Language Reference 47 CHAPTER 2 Basic Building Blocks Object Class Class Object is the superclass of all other classes and defines the protocol common to all objects. For example, class Object defines the default behavior for displaying, comparing, copying, hashing, and inspecting objects, accessing indexed instance variables; and handling errors. It includes capabilities to maintain dependency relationships between objects and to broadcast messages from an object to its dependents. It also provides the entry point for interrupt handling. Creating and Destroying Instances One of the many things that all classes can do is to create new instances of themselves. This is ordinarily accomplished using the class messages new or new:. When a new instance of a class is created, it is automatically initialized by being sent the message initialize or initialize:, depending on whether the instances was created using new or new:, respectively. new and new: Create a new instance of the receiver. If the receiver is a class that has indexable instance variables, new creates an instance with none. new: is understood only by classes with indexable instance variables, and creates the number of indexable instance variables specified. initialize and initialize: The default implementations do nothing. If new instances of a class require initialization, redefine these methods for the class. When you define a subclass, define a class method initialize to initialize the class as necessary, for example to initialize class variables. Some objects, particularly those using operating system resources, may need to perform explicit clean-up operations before the garbage collector can reclaim the memory they use. These messages perform some clean-up operations: free Releases the memory associated with the receiver. For example, ExternalGlobalAddress>>free. release Performs the clean-up necessary to allow the receiver to be garbage collected. A subclass may need to override it.

48 Visual Smalltalk Enterprise Language Reference Object Class

Accessing Instances There are a number of other operations that all objects in the system can do. For example, all objects can tell you what class they are an instance of when you send them the message class. class Returns the class of the receiver. Objects reply to the size method by returning their number of instance variables. Note that his methods is overridden by several classes, especially by collections: size Returns the number of instance variables the receiver has. All objects with indexable instance variables understand the messages at: and at:put:. at: Returns the value of the instance variable at the specified index. at:put: Puts the specified value at the specified index. Certain classes may need to override these methods to perform operations more specific to the particular purpose of the class. Such classes can rely on the messages basicAt:, basicAt:put:, and basicSize to perform the operations specified above. Do not override these basic methods. Equality and Identity If two objects are equal, they have the same behavior at this particular point in time (although they might not later). If two objects are identical, they are the same object and are represented by the same memory. The following messages allow you to determine if two objects are equal or not: = Returns true if the receiver is equal to the argument. ~= Returns true if the receiver is not equal to the argument. The following messages allow you to determine if two objects are identical or not:

Visual Smalltalk Enterprise Language Reference 49 CHAPTER 2 Basic Building Blocks

== Returns true if the receiver is identical to the argument. ~~ Returns true if the receiver is not identical to the argument. The message yourself can be sent to any object to return the object itself. This message is often used at the end of a message cascade to return the receiver. Hash Values Each object in the system has an associated hash value, The system requires that if two objects are equal they must have equal hash values. To determine the hash value of an object, send it the message hash, which returns the integer hash value of the receiver. If you override the messages = and ~= for a class you define, you must also override the method hash so that the system requirement is satisfied. Otherwise, your application may not behave as you intended. Each object in the system also has an associated basic hash value. The system requires that identical objects must have equal basic hash values. To determine the basic hash value of an object, send it the message basicHash, which returns the integer basic hash value of the receiver.

CAUTION: Do not override the messages ==, ~~, or basicHash for any class.

Testing Visual Smalltalk contains a number of methods that allow you to determine if a particular object is a certain kind of object or can behave in a particular way. By convention, such methods are defined to test for the behavior. Their message selectors take the form isFoo, where foo is the behavior of interest. For example, isNumber or isCollection. Your code will be more portable and extensible, as well as faster, if you conform to this convention, instead of testing to see if the object is of a particular class (with class) or inherits from a particular class (with isKindOf:).

50 Visual Smalltalk Enterprise Language Reference Object Class

Copying All objects can return a copy of themselves. A copy of an object is an object that, at the moment it is created, is equal to the original object but independent of it. That is, later changes to either the original or the copy do not change the other. copy Returns an object that is equal to the receiver. If the receiver is unique or immutable, it is not copied. This method sends the message shallowCopy, which you can override if you wish to change the implementation of copy. Evaluating Messages Objects evaluate messages by being sent the message perform: or one of its variants. The argument to perform: is the specified message selector. perform: Causes the receiver to evaluate the unary message selector sent as the argument, and returns the result. perform:withArguments: Causes the receiver to evaluate the keyword message selector sent as the argument to perform:, with an array of arguments given as the argument to withArguments:. Returns the result. If the receiver is unable to respond to the message selector specified as the argument to perform:, or if the wrong number of arguments is sent, the message doesNotUnderstand: is used to handle the error. perform:with: Causes the receiver to evaluate the binary or keyword message selector sent as the argument to perform:, with the single argument given as the argument to with:. Returns the result. perform:with:with: Causes the receiver to evaluate the keyword message selector sent as the argument to perform:, with the two arguments given as the arguments to with:with:. Returns the result. perform:with:with:with: Causes the receiver to evaluate the keyword message selector sent as the argument to perform:, with the three arguments given as the arguments to with:with:with:. Returns the result.

Visual Smalltalk Enterprise Language Reference 51 CHAPTER 2 Basic Building Blocks

Events Objects can use events to announce that something has occurred that is of possible interest to other objects. The object is said to trigger the event. Other objects can respond to an event if they are interested, usually by sending a message. The event mechanism allows for a looser coupling of objects than is provided by messages alone. When one object sends a message to another object, it is placing a demand on that object to do something. By triggering an event instead, an object can make a general announcement, leaving it up to the other objects to decide if they need to do anything in response. The triggering object doesn’t care if other objects are interested. If an object is interested, it registers a handler for that event with the triggering object. This must be done in advance, so while designing the application you must know what events are liable to be raised and what objects should register handlers. Events are commonly used to coordinate window pane actions. They are also of more general usefulness throughout a Visual Smalltalk application for communicating between objects. Defining Events By default, any object can trigger any event. For many classes, however, it is useful to be able to specify more carefully just which events a class of objects can trigger. Notably, classes ApplicationCoordinator, Window, and a few others include methods for specifying precisely what events they can trigger. Subclasses of these classes must identify the events that objects of that class can trigger. You may also implement similar mechanisms in your own classes. The events that instances of these classes and subclasses can trigger are defined in the class instance variable eventsTriggered. The variable is defined by the top level classes and is inherited by their subclasses. Since this is a class instance variable, its value is not inherited, and each subclass must construct its own set of events. Each class initializes eventsTriggered to be a Set, and then adds event names as values. The Window class, for example, initializes the set in its constructEventsTriggered class method:

52 Visual Smalltalk Enterprise Language Reference Object Class

constructEventsTriggered "Private - answer the set of events that instances of the receiver can trigger." ^Set new Each subset implements its own constructEventsTriggered class method to initialize its own instance of eventsTriggered and to add events to it. Any message for adding elements to a set can be used. For example, TopPane uses addAll: to add events listed in an array: constructEventsTriggered "Private - answer the set of events that instances of the receiver can trigger." ^super constructEventsTriggered addAll: #( aboutToClose aboutToDisplayMenu activated closed deactivated help menuBarBuilt opened rightClicked timer: validated ); yourself The constructEventsTriggered message should only be sent by the initializeEventsTriggered method, which is inherited and invoked by the class initialization method. Once an event name is listed and the class initialized, any instance of the class can trigger that event. Event Names Event names use the same notation as message selectors to denote unary and keyword events. Keyword events provide an event value, where the triggering object supplies one or more values when it triggers the event. Unary events do not provide an event value. For example, a Button triggers the unary event clicked when it is pressed. No event value is passed. A ListBox, on the other hand, triggers the keyword event changed: when a new item is selected in the list, and passes the new selection as its event value.

Visual Smalltalk Enterprise Language Reference 53 CHAPTER 2 Basic Building Blocks

Triggering Events Any object can trigger any event in its class eventsTriggered list. It does so simply by sending some form of the triggerEvent: message to itself. For example: self triggerEvent: #changed The following messages are used to trigger an event: triggerEvent: eventName Trigger the event eventName. Answer the value returned by the most recently defined event handler action, or nil if there are no actions defined for the event. triggerEvent: eventName ifNotHandled: exceptionBlock Trigger the event eventName. If the event is not handled, answer the value of exceptionBlock. Otherwise, answer the value returned by the last action that is evaluated. triggerEvent: eventName with: anArgument Trigger the event eventName using the given anArgument as the argument. Answer the value returned by the last action that is evaluated, or nil if there are no actions defined for the event. triggerEvent: eventName with: firstArgument with: secondArgument Trigger the event eventName using firstArgument and secondArgument as the arguments. Answer the value returned by the last action that is evaluated, or nil if there are no actions defined for the event. triggerEvent: eventName withArguments: argumentArray Trigger the event eventName using the elements of the argumentArray as the arguments. Answer the value returned by the last action that is evaluated, or nil if there are no actions defined for the event. triggerEvent: eventName withArguments: argumentArray ifNotHandled: exceptionBlock Trigger the event eventName using argumentArray as the arguments to the action. If the event is not handled, answer the value of exceptionBlock. Otherwise, answer the value returned by the last action that is evaluated, or nil if there are no actions defined for the event.

54 Visual Smalltalk Enterprise Language Reference Object Class

Configuring Event Actions Any object can associate some action with another object by registering an event handler with that object. An action is any evaluable action, typically a message or a block. By registering a handler for an event, you can cause other actions to occur when an event is triggered. To determine whether a class or an instance can trigger an event, send the canTriggerEvent: to the object. There are both class and instance versions of this message defined in Object. Some classes also implement an eventsTriggered message, which returns a collection of the events in the object’s event table. To register a handler, an object sends some form of the when:send: message to the triggering object. The argument to when: is a symbol giving the event name. The remaining arguments specify a receiver, a message selector and arguments, or an evaluable object. For example, suppose you create a window with a Close button to close the window, and you want the window to close when the user clicks on the button. The button triggers the clicked event when clicked on. You also have a method that closes the window, called close. To register the action for the event, your application sends the registration message to the button: when: #clicked send: #close to: self When the button is pressed, it triggers the clicked event. Since the event has been registered, the button sends close to the application. The same registration message is used with a keyword event. For example, to register a handler for a list box changed: event, you might send this message to the list box: when: #changed: send: #listItemSelected: to: self When the list box triggers the changed: event, it sends listItemSelected: to the application with the newly selected item as the argument. You can also register event handlers that pass additional arguments. You do this if the handling method requires additional information. For example, this fragment registers a handler that provides the triggering object as the evaluation argument: topPane addSubpane: ((aTextPane := TextPane new) when: #needsContents send: #updateContentsOf: to: self with: aTextPane)

Visual Smalltalk Enterprise Language Reference 55 CHAPTER 2 Basic Building Blocks

When the text pane triggers the needsContents event, it sends the message updateContentsOf: to the application with the text pane as the argument. The event handler must be an evaluable object, usually a message or a block. The handler can be an instance of ActionSequence, which is an ordered collection of evaluable actions. Actions must respond to the message asActionSequence by answering an ActionSequence containing the action. The following registration messages are used to register actions for events. when: eventName evaluate: anAction Append anAction to the list of actions to evaluate when the receiver triggers the event named eventName. when: eventName do: responseBlock Append responseBlock to the list of actions to evaluate when the receiver triggers the event named eventName. when: eventName send: aSelector to: anObject Form an action with anObject as the receiver and aSelector as the message selector, and append the action to the handler list for eventName. when: eventName send: aSelector to: anObject with: anArgument Form an action with anObject as the receiver, aSelector as the message selector, and anArgument as the argument, and append the action to the handler list for eventName. when: eventName send: aSelector to: anObject with: firstArgument with: secondArgument Form an action with anObject as the receiver, aSelector as the message selector, and firstArgument and secondArgument as the arguments, and append the action to the handler list for eventName.

56 Visual Smalltalk Enterprise Language Reference Object Class

when: eventName send: aSelector to: anObject withArguments: argumentArray Form an action with anObject as the receiver, aSelector as the message selector, and the elements of argumentArray as the arguments, and append the action to the handler list for eventName. Reporting Exceptions Three main messages are used in Visual Smalltalk to report error conditions. You may need to reimplement these methods in your classes: doesNotUnderstand: The interpreter sends this message to the receiver of the perform: messages if the message receiver cannot respond to the selector. implementedBySubclass Use this message as a placeholder method in an abstract superclass which must be reimplemented by its subclasses. In this way, an abstract superclass can specify methods without defining their behavior. invalidMessage Use this message to remove behavior inherited by a subclass. Subclasses generally implement a superset of the behavior of their superclasses. This methods gives a way to override that general case. Refer to chapter 7 for a full discussion of exception handling. Object Descriptions Objects can describe themselves by producing either human readable text or a source code string that can be compiled and evaluated to produce a copy of the object. The following messages are available to accomplish this. printOn: Sends a text string that describes the receiver to the stream specified as the argument. printString Returns a text string that describes the receiver, using printOn:.

Visual Smalltalk Enterprise Language Reference 57 CHAPTER 2 Basic Building Blocks

storeOn: Sends a Smalltalk expression to the stream specified as the argument. When evaluated, the expression creates a copy of the receiver. storeString Returns a Smalltalk expression that, when evaluated, creates a copy of the receiver, using storeOn:. Reimplement only the printOn: and storeOn: methods in your class. Object Finalization Finalization is a mechanism that allows an object to specify an action to be performed before it is garbage collected. It is important for some objects, such as bitmaps and other objects that use external memory resources, that perform some cleanup operations before their Smalltalk memory is garbage collected. In the case of bitmaps, this means releasing the external memory. While finalization makes for a good backup strategy for making sure that such cleanup operations are performed, it should not be used in place of explicit cleanup performed by the application. Applications are still responsible for releasing any resources they use. There are potential long delays between the time when the last reference to an object is destroyed and the time when the object is finalized and garbage collected. Accordingly, it is better for an application to explicitly release its resources, and rely on finalization only as a backup. Most of the finalization mechanism is implemented in Object. To use finalization for any objects you create, you only need to register the object for finalization notification, and implement a method to do any cleanup processing. To register an object for finalization, send the message needsFinalization to self, the object itself. The default method, defined in Object, registers the object so that it will be sent the finalize message before it is garbage collected. You can de- register the object by sending it the doesNotNeedFinalization message. Finalization processing is defined in the finalize method, implemented by the object needing finalization. The default implementation in Object does nothing. The exact processing that is appropriate will depend on the object itself. As an example, the implementation for Bitmap is simply to release the object:

58 Visual Smalltalk Enterprise Language Reference Boolean Classes

finalize "Private - Receiver has been garbage collected, release the host resource." self release. To find out if an object is registered for finalization, send it the message hasFinalization. The message returns a Boolean. A manager object may need to know when some object other than itself is about to be garbage collected. In this case, the manager object sends itself the notifyWhenFinalizable: message, with the object needing finalization as the argument. When the garbage collector determines that the specified object has no more references, it sends the finalize: message to the manager object, again with the finalizable object as argument. The manager implements finalize: to perform the necessary processing. To deregister the object, send doNotNotifyWhenFinalizable:. For more information on object finalization, refer to Object Finalization in chapter 16. Boolean Classes Class Boolean is an abstract class that defines the common protocol for logical values. The logical values are represented by its two subclasses: True and False, each of which has only a single instance: true and false, respectively. Boolean Expressions In Visual Smalltalk, the class Boolean has two subclasses: True and False. These classes implement some of the basic messages available to control the flow of execution in your application. For example, the messages ifTrue:, ifFalse:, ifTrue:ifFalse:, and ifFalse:ifTrue: allow you to execute code on a conditional basis. The classes True and False also define certain familiar Boolean operations: & Returns the value of the conjunction, the logical AND, of the receiver and the argument, which must both be Boolean values. and: Returns the value of the conjunction, the logical AND, of the receiver and the argument. The argument must be a block that evaluates to a Boolean value. not Returns the logical negation of the receiver.

Visual Smalltalk Enterprise Language Reference 59 CHAPTER 2 Basic Building Blocks

xor: Returns the value of the exclusive disjunction, the exclusive OR, of the receiver and the argument, which must both be Boolean values. | Returns the value of the disjunction, the logical inclusive OR, of the receiver and the argument, which must both be Boolean values. or: Returns the value of the disjunction, the logical inclusive OR, of the receiver and the argument. The argument must be a block that evaluates to a Boolean value.

The and: and or: messages are similar to & and |, but require the argument to be a block rather than a Boolean value. The block is evaluated only if its value is required to determine the result of the logical operation. For details on blocks, see the section entitled Blocks in chapter 1. Magnitude Classes The magnitude classes are the easiest to understand and the most frequently used. They define objects that can be compared, measured, ordered, and counted. These include characters, numbers, dates, and times. Many useful messages for comparing, testing, and ordering these objects are defined. The arithmetic operators and many useful numerical functions are also defined as messages understood by the numerical magnitude objects. This section presents a quick overview of each of the magnitude classes provided in Visual Smalltalk. The Encyclopedia of Classes gives a detailed specification of each of the magnitude classes. The Magnitude class hierarchy shown below lists all of the magnitude classes.

60 Visual Smalltalk Enterprise Language Reference Magnitude Classes

Magnitude Association Character Date Number Float Fraction Integer LargeInteger LargeNegativeInteger LargePositiveInteger SmallInteger Time TimeStamp Magnitude All magnitude classes are subclasses of the abstract class Magnitude. Class Magnitude provides the comparing and ordering protocol inherited by its subclasses. All magnitude classes support comparing, ordering, and interval testing. Magnitude assumes its subclasses implement the ordering relation and comparison methods: = Returns true if the receiver is equal to the argument. < Returns true if the receiver is less than the argument. <= Returns true if the receiver is less than or equal to the argument. > Returns true if the receiver is greater than the argument. >= Returns true if the receiver is greater than or equal to the argument. ~= Returns true if the receiver is not equal to the argument. between:and: Returns true if the receiver is between the first argument and the second argument, inclusive.

Visual Smalltalk Enterprise Language Reference 61 CHAPTER 2 Basic Building Blocks

min: Returns whichever is smaller, the receiver or the argument. If they are equal, this message returns the receiver. max: Returns whichever is larger, the receiver or the argument. If they are equal, this message returns the receiver. Based on these methods, Magnitude provides generic methods for interval testing and max/min computation inherited by all magnitude classes. Some numerical examples are:

Expression Answer

46 > 33 true 46 min: 33 33 46 max: 33 46 5/4 between: 0.5 and: 1 false

Character The instances of class Character are the extended ASCII character set from ASCII value 0 to ASCII value 255. Characters are pre- existing objects in Smalltalk, hence they do not have to be created. References to characters are made in two ways: as literals or by converting integers into the corresponding ASCII character. There are two conversion messages. The message asCharacter can be sent to an integer, or the message value: with an integer argument can be sent to class Character. For example:

Character Literal Equivalent Expression

A $A 65 asCharacter B $B 66 asCharacter

C $C Character value: 67 tab -- Character value: 9 line feed -- 10 asCharacter space $ 32 asCharacter

62 Visual Smalltalk Enterprise Language Reference Magnitude Classes

Like all subclasses of Magnitude, the class Character must define how characters are compared and ordered. The methods <, <=, =, >=, > and ~= compare characters by comparing their ASCII values. In addition, the interval and min/max methods are inherited from class Magnitude automatically. For example:

Expression Answer

$a = $A false $A < $B true 69 asCharacter max: $A $E $x between: $a and: $t false

Early versions of Smalltalk assumed that instances of the class Character were unique and immutable. Because double-byte encodings allow a far greater range of characters, this is no longer true. Instances of the same character are not guaranteed to be the same object. Therefore, code that used to test for identity should now test for equality. Class Character also has many testing methods. The following are a few of the most commonly useful methods: isDigit Returns true if the receiver is between 0 and 9. isLetter Returns true if the receiver is a letter of the alphabet, either upper-case or lower-case. isLowerCase Returns true if the receiver is a lower-case letter of the alphabet. isSeparator Returns true if the receiver is a space, a tab, a carriage return, a line feed, or a form feed character. isUpperCase Returns true if the receiver is an upper-case letter of the alphabet.

Visual Smalltalk Enterprise Language Reference 63 CHAPTER 2 Basic Building Blocks

For example:

Expression Answer

$a isUpperCase false $a isLowerCase true $a asUpperCase $A $? asLowerCase $? $e isVowel true $+ isLetter false $9 isDigit true $A asciiValue 65

In addition, the class Character supports a variety of conversion messages. A few of the most commonly useful are described below. asLowerCase Returns the lower-case equivalent of the receiver, if the receiver is a letter of the alphabet. Otherwise, returns the receiver. asUpperCase Returns the upper-case equivalent of the receiver, if the receiver is a letter of the alphabet. Otherwise, returns the receiver. digitValue Returns the value of the receiver when interpreted as a digit for the radix. If the receiver is not a valid digit, an error is reported. Note that you can create instances of Character, if necessary, using the message value:. value: Returns an instance of a Character having the specified integer encoding.

64 Visual Smalltalk Enterprise Language Reference Magnitude Classes

Date, Time and TimeStamp Instances of class Date represent specific dates such as January 1, 1980 or September 15, 1876. Instances of class Time represent specific times of the day such as 10 am or 12:15 pm. Dates and times are created by evaluating expressions. The detailed descriptions in the Encyclopedia of Classes give a complete list of the messages supported by Date and Time. The following message can be sent to either class to create an instance of the current date and time. dateAndTimeNow Returns an array of two elements: the first is an instance of Date representing the current date; the second an instance of Time representing the current time. New instances of class Date can be created with the following class message: newDay:month:year: Returns a new instance of the class Date as specified by day, month and year integer values. New instances of class Time can be created with the following message: hours:minutes:seconds: Returns an instance of the class Time as specified by hour, minutes, and seconds in integer values. now Returns an instance of the class Time representing the current time. For example: Time now Date today '20 January 1950' asDate Date newDay: 20 month: #Jan year: 1950. The date and time are combined in instances of TimeStamp. The following two class methods create new instances: current Returns the current date and time as a time stamp. date:time Returns a time stamp, with the date given by an instance of Date and the time given by an instance of Time.

Visual Smalltalk Enterprise Language Reference 65 CHAPTER 2 Basic Building Blocks

The following code makes an instance of class Date and puts it in the global variable Birthday: Smalltalk at: #Birthday put: '4 August 1976' asDate Ordering and comparing of dates and times are supported. Some examples of messages supported by Date are:

Expression Answer

Birthday year 1976 Birthday dayName Wednesday Birthday > Date today false Birthday min: Date today 'Aug 4, 1976' Birthday 'Jul 31, 1976' previousWeekday: #Saturday

Birthday 149 daysLeftInYear Birthday daysInYear 366

You can add new ways of creating objects by defining new methods. You add the following method as a class method in class Time: hour: hours minute: minutes second: secs "Answer an instance of class Time as specified" ^ self fromSeconds: ((( hours * 60) + minutes) * 60) + secs Then, you can create instances of class Time using expressions like the following: Smalltalk at: #LunchTime put: (Time hour: 12 minute: 0 second: 0). Smalltalk at: #DinnerTime put: (Time hour: 18 minute: 45 second: 0). Smalltalk at: #BreakfastTime put: (Time hour: 7 minute: 30 second: 0). Some examples using these new global variables are:

Expression Answer

LunchTime true between: BreakfastTime and: DinnerTime

66 Visual Smalltalk Enterprise Language Reference Magnitude Classes

Expression Answer LunchTime min: 12:00:00 DinnerTime

DinnerTime hours 18 LunchTime < false BreakfastTime

Numbers Smalltalk supports three kinds of numbers, which are subclasses of the class Number: • Floating point (class Float) • Rational (class Fraction) • Integer (class Integer and its subclasses) The methods of class Number define the general behavior of its subclasses, support mixed-mode arithmetic, and provide many useful numeric, testing, and iteration functions. Number defines the arithmetic protocol that its subclasses must implement. These are the usual binary arithmetic operators: +, -, *, and /. Evaluation is left to right, with equal precedence between all binary operators. For example:

Expression Answer 3 + 4 7 3 + 4 * 2 14 2 + 4 / 12 1/2

Number implements many numerical methods that its subclasses can inherit such as: exp, cos, arcSin, tan, ln, sqrt, floor, abs, and reciprocal. Some examples:

Expression Answer 7.5 floor 7 4 reciprocal 1/4 2.3 abs 2.3

Visual Smalltalk Enterprise Language Reference 67 CHAPTER 2 Basic Building Blocks

Number implements many testing methods inherited by its subclasses such as: even, positive, and strictlyPositive. Some examples:

Expression Answer

4 even true 0.1 positive true 0 strictlyPositive false

Number implements methods for creating other kinds of objects, such as:

Expression Answer

2 @ 7 Point with x coordinate = 2 and y coordinate = 7 1/4 to: 3/4 by: 1/8 An Interval containing the fractions 1/4, 3/8, 1/2, 5/8, 3/4

Number also implements iteration methods, such as: 1/4 to: 1.5 by: 1 do: [:i | Transcript space; nextPutAll: i printString; cr] which prints the numbers 1/4 and 5/4 in the Transcript window. Visual Smalltalk supports mixed-mode arithmetic so that arithmetic expressions can be composed of different kinds of numbers. Executing sample expressions is the best way to understand the conversion rules.

Expression Answer Comment

1 + 2 3 5.1 - 3 2.1 Note space between - and 3

2 * -4.0 -8.0 Mixed-mode gives a float 2/4 1/2 A fraction 1/2 + 1 3/2 Mixed-mode gives a fraction 1/2 + 1.0 1.5 Mixed-mode gives a float 4/2 2 Fraction reduces to an integer

68 Visual Smalltalk Enterprise Language Reference Magnitude Classes

The following examples explain many of the messages that can be used with Number.

Expression Answer Comment

4 // 3 1 Integer quotient -4 // 3 -2 Truncate toward minus infinity 4 \\ 3 1 Integer remainder -4 \\ 3 2 Integer remainder, truncates as // -4 quo: 3 -1 Integer quotient, truncate toward zero -4 rem: 3 -1 Integer remainder, truncate toward zero -2.3 abs 2.3 Absolute value 10 negated -10 Negation 11 reciprocal 1/11 A fraction 2 + 3 * 4 20 Evaluation is left to right 3 - (2 * 2) -1 Parentheses change evaluation order 2 + 3 negated -1 Unary operator (negated) done first 6 quo: 2 + 1 2 Keyword operator (quo:) done last 2 sqrt 1.4142135 Square root 4 sqrt 2.0 Answer always float 2.1 squared 4.41 Receiver times itself 2.3 even true 2 odd false 10 negative false

0 positive true True if >= 0

0 strictlyPositive false True if > 0 -0.1 sign -1 0 sign 0 100 sign 1 5.1 ceiling 6 Nearest integer greater than or equal -5.1 ceiling -5 5.1 floor 5 Nearest integer less than or equal

Visual Smalltalk Enterprise Language Reference 69 CHAPTER 2 Basic Building Blocks

Expression Answer Comment -5.1 floor -6 5.1 truncated 5 Nearest integer toward zero -5.1 truncated -5 5.1 rounded 5 Nearest integer 5.1 truncateTo: 2 4 Nearest argument multiple toward zero 5.1 truncateTo: 2.3 4.6 5.1 roundTo: 2 6 Nearest argument multiple

5.1 roundTo: 2.3 4.6 5 exp 148.41315 Exponential 2.7182819 ln 1.0000003 Natural logarithm 4 log: 2 2.0 The logarithm in the base of the argument 3 raisedTo: 1.1 3.3483695 The receiver to the power of the argument 4 raisedToInteger: 3 64 Receiver to the power of the integer argument 30 degreesToRadians 5.23598776e-1 Convert degrees to radians 2 radiansToDegrees 114.591559 Convert radians to degrees 0.52359878 sin 0.5 Angle in radians 0.72273425 cos 7.49999999e-1 0.24497866 tan 2.49999997e-1 0.5 arcSin 5.23598776e-1 Angle in radians

0.75 arcCos 7.22734248e-1

0.25 arcTan 2.44978663e-1

Float An 8-byte IEEE format is used for instances of class Float to approximate real numbers. This gives approximately 18 digits of precision and represents values in the range (+/-)4.19e-307 to (+/-)1.67e308. If your computer has an 80387 or compatible math coprocessor, Visual Smalltalk will access it with the full speed and precision offered by these optional arithmetic chips.

70 Visual Smalltalk Enterprise Language Reference Magnitude Classes

Fraction Instances of class Fraction are exact representations of rational numbers. A pair of integers (instance variables, numerator and denominator) describes the fraction. Fractions are created by sending the slash (/) message to an integer with an integer argument (provided that the answer does not reduce to an integer). For example, the expression 3/4 creates an instance of a Fraction by sending the message / to the integer 3 with the argument 4. This operation returns the exact result of the division and not a floating-point approximation. Integer Integers are frequently used in counting and indexing. The class Integer contains the following subclasses: Integer LargeInteger LargeNegativeInteger LargePositiveInteger SmallInteger Table 4-1 shows the range of values that these classes support. Note that although instances of class SmallInteger are in the range -1,073,741,824 to 1,073,741,823, any value outside this range is represented by an instance of LargePositiveInteger or LargeNegativeInteger.

Table 2-1: Range Supported by Integer Classes

Class Range SmallInteger -1,073,741,824 to 1,073,741,823 LargePositiveInteger greater than 1,073,741,823

LargeNegativeInteger less than -1,073,741,824

These classes are highly efficient in both computing speed and memory occupation. Small integers are encoded in the reference to the object (the object pointer). They are not represented as objects in memory. The large integer classes can represent numbers with unlimited bytes of precision. Conversion between integer classes is automatic. Two sets of message selectors allow you to access the quotient and remainder after performing division.

Visual Smalltalk Enterprise Language Reference 71 CHAPTER 2 Basic Building Blocks

// Returns the integer quotient of dividing the receiver by the divisor given as the argument, with truncation toward negative infinity. \\ Returns the integer remainder of dividing the receiver by the divisor given as the argument, with truncation toward negative infinity. quo: Returns the integer quotient of dividing the receiver by the divisor given as the argument, with truncation toward zero. rem: Returns the integer remainder of dividing the receiver by the divisor given as the argument, with truncation toward zero. Collection Classes The class Collection is an abstract class defining the behavior common to all objects that contain other objects. It implements a number of common operations: creating instances, converting one kind of collection to another, enumerating all the objects in a collection, and determining an object’s size, whether it is empty, whether it includes a given object, and if so, how many times. includes: Returns true if the receiver contains an element equal to the argument. isEmpty Returns true if the receiver contains no elements; otherwise returns false. notEmpty Returns true if the receiver contains elements; otherwise returns false. occurrencesOf: Returns the number of elements in the receiver that are equal to the argument. size Returns the number of elements in the receiver.

72 Visual Smalltalk Enterprise Language Reference Collection Classes

Attributes of the Collection Class In general, each kind of collection can be characterized by four attributes: • Whether the collection has a well-defined order associated with its elements. This order can be defined either externally by a key or internally by the contents of elements. • Whether the collection’s size is fixed or expandable. • Whether or not duplicates of the collection’s elements are allowed. • Whether the collection’s accessible by a set of keys. Keys can be either integer indices or lookup keys. In the table that follows, the only collections that have the same attribute values are the String-Symbol, DoubleByteString- DoubleByteSymbol, and DictionaryIdentityDictionary pairs. The difference between a String and a Symbol, and between a DoubleByteString and a DoubleByteSymbol, is that a symbol is guaranteed to be unique while a string can have many copies. The difference between a Dictionary and an IdentityDictionary is that during the key lookup comparison, the former uses the = message while the latter uses ==. The following table shows the attributes of each class:

Fixed Element Ordered Size Dup’s Keys Class Bag No Yes None any IndexedCollection* Yes N.A. N.A. Integer N.A. FixedSizeCollection* Yes Yes Yes Integer any Array Yes Yes Yes Integer any ByteArray Yes Yes Yes Integer SmallInteger (0<= n <256) Interval Internal Yes No Integer Number String Yes Yes Yes Integer Character Symbol Yes Yes Yes Integer Character DoubleByteString Yes Yes Yes Integer Character DoubleByteSymbol Yes Yes Yes Integer Character OrderedCollection Yes No Yes Integer any

Visual Smalltalk Enterprise Language Reference 73 CHAPTER 2 Basic Building Blocks

Fixed Element Ordered Size Dup’s Keys Class SortedCollection Internal No Yes Integer any Set No No No Dictionary No No No Lookup any IdentityDictionary No No No Lookup any

Notes: * Abstract classes, there are no instances Internal: ordered by the internal contents of the collection N.A.: not applicable (determined by subclasses) Enumerating Collections Enumerating messages allow you to process all the elements of a collection. Enumerating messages usually take a one-argument block as an argument that they evaluate with each element in the receiver collection. Assume Customer and Supplier have the same values. | count | count := 0. Customer do: [:aName | count:= count + aName size]. ^ count produces 17. Customer select: [:aName | aName == #John] produces Bag ( John John John ). Customer reject: [:aName | aName == #John] produces Bag ( Peter ). Customer collect: [ :aName | aName asArray] produces Bag ( ($J $o $h $n ) ($J $o $h $n ) ($J $o $h $n) ($P $e $t $e $r) ) Customer detect: [ :aName | aName includes: $P] produces Peter. Customer detect: [ :aName | aName = #Mary] ifNone: ['Not found'] produces “Not found.”

74 Visual Smalltalk Enterprise Language Reference Collection Classes

Customer inject: 0 into: [ :count :aName | count + aName size] produces 17. The following messages are useful for enumerating all the elements in a collection. collect: Returns a collection whose elements are the result of evaluating the block provided as an argument for each element in the receiver. detect: Returns the first element of the receiver for which the block provided as an argument evaluates to true. If the block does not return true for any element, sends the message errorAbsentObject to the receiver. detect:ifNone: Returns the first element of the receiver for which the block provided as an argument to detect: evaluates to true. If the block does not return true for any element, returns the value of the block provided as an argument to the ifNone: keyword. do: Evaluates the block provided as an argument once for each element in the receiver. If the receiver is empty, the block is not evaluated. inject:into: The block provided as an argument to the into: keyword is evaluated once for each element of the receiver. The element is the second argument to the block. On the first evaluation, the first argument is the argument to the inject: keyword. On subsequent evaluations, the first argument is the result of the previous evaluation. Returns the result of the final evaluation. If the receiver is empty, returns the initial value. reject: The block provided as an argument is evaluated once for each element of the receiver. Returns a collection whose elements are the elements of the receiver for which the block evaluates to false. select: The block provided as an argument is evaluated once for each element of the receiver. Returns a collection whose

Visual Smalltalk Enterprise Language Reference 75 CHAPTER 2 Basic Building Blocks

elements are the elements of the receiver for which the block evaluates to true. Converting Collections Because the various collection classes have different attributes, being able to convert from one kind of collection to another is useful. Visual Smalltalk provides the following conversion protocol in class Collection. asArray Ordering is possibly arbitrary. asBag Duplicates are kept. asSet Duplicates are eliminated. asOrderedCollection Ordering is possibly arbitrary. asSortedCollection Each element is less than or equal to its successor. asSortedCollection: sortBlock Ordering is specified by sortBlock. Thus, any collection can be converted into an Array, a Bag, a Set, an OrderedCollection, or a SortedCollection. Creating Instances Like other classes, the message new can be used to create an instance of any collection. The message new: can be used to create a fixed-size collection with a specified size and a variable- size collection with a specified initial allocation size. Some collections may be expressed in literal form:

Class Instance in literal Form String 'John Mary' Symbol #John Array #($J 'John' John (John 3) )

A literal string is enclosed in a pair of quotes, a literal symbol is preceded by a number sign (#), and a literal array is enclosed in paired parentheses and preceded by a number sign. The Array

76 Visual Smalltalk Enterprise Language Reference Collection Classes

example contains four elements: a character, a string, a symbol, and another array which has two elements—a symbol and a small integer. Notice that within a literal array, a symbol or another array element must not be prefixed with a number sign. You can create an instance of a specific subclass of Collection by sending the class the message with:. The argument to with: is the first element of the collection. Variants of this message repeat the keyword up to four times, allowing you to initially create collections with up to four elements, which are not necessarily constants. For example, Array with: 'Daughters of John' with: #('Ann' 'Mary') creates an array with two elements: a string and another array of two elements. Common Protocol Visual Smalltalk provides common protocol to manipulate collections in a uniform way. These can be categorized as adding new elements, removing elements, testing the occurrences of elements, and enumerating elements. These are all described in the Encyclopedia of Classes under class Collection. Suppose you have two global variables, Customer and Supplier, initialized as: Customer:= Bag with: #John. Supplier:= #(John Peter). Then you send adding, removing, and testing messages to Customer:

Customer value Expression Answer if changed Customer add: #Bob Bob Bag(John Bob)

Customer addAll: Supplier (John Peter) Bag(John John Peter Bob) Customer removeAll: Supplier (John Peter) Bag(John Bob) Customer removeAll: Supplier error Bag(Bob) Customer remove: #Bob Bob Bag( ) Customer isEmpty true Customer occurrencesOf: #John 0 Customer includes: #John false

Visual Smalltalk Enterprise Language Reference 77 CHAPTER 2 Basic Building Blocks

Customer value Expression Answer if changed Customer addAll: #(John John) (John John) Bag(John John) Customer addAll: Supplier (John Peter) Bag(John John John Peter) Customer occurrencesOf: #John 3

Class Bag Class Bag defines objects that contain collections of arbitrary objects. Duplicates are allowed, and ordering is arbitrary. A bag does not have external keys, so it cannot respond to the messages at: and at:put:. Since a bag can hold arbitrarily many instances of an object, it has a message, add:withOccurrences: to add an element a specified number of times. Bags are implemented as dictionaries for efficient storage and lookup. As an example, here is an expression that computes the frequency of the occurrence of words in a file. | input frequency output word | input := File pathName: 'in.fil'. output := File pathName: 'out.fil'. frequency := Bag new. [(word := input nextWord) isNil ] whileFalse: [frequency add: word asLowerCase ]. frequency asSet asSortedCollection do: [ :word | output nextPutAll: word; tab; nextPutAll: (frequency occurrencesOf: word) printString; cr]. input close. output close. Class HashedCollection HashedCollection is an abstract class for collection classes that sort their contents based on hash value. The classes Set and Dictionary are subclasses of HashedCollection.

78 Visual Smalltalk Enterprise Language Reference Collection Classes

Class Set A Set is like a Bag except that it cannot have duplicate elements. Sets are hashed for efficient lookup. As an example, here is an expression that computes a sorted list of words in a file. | input words word | input := File pathName:'in.fil'. words := Set new. [ (word := input nextWord) isNil ] whileFalse: [words add: word asLowerCase]. input close. ^ words asSortedCollection. Class Dictionary Class Dictionary represents a set of objects with external lookup keys. Dictionaries are hashed for efficient lookup. The elements of a Dictionary are instances of class Association, and contain a lookup key and its corresponding value. Because the key is only for lookup purposes, the messages includes:, do:, and other inherited enumeration messages are applied to the values rather than to the keys or to the associations themselves. Class Dictionary provides other messages to deal with keys and associations. Class IdentityDictionary Class IdentityDictionary is similar to Dictionary except that it uses identity (==) instead of equality (=) during a key lookup. Its implementation, which does not use associations, makes storage in and IdentityDictionary more efficient than in a Dictionary. Its key lookup matches object pointers, rather than object contents, so the most sensible classes for its keys are Character, Symbol, and SmallInteger. Class IndexedCollection Class IndexedCollection represents collections with elements ordered externally by integer indices. It is an abstract class to contain common protocol for its subclasses and, therefore, should not have any instance of its own created.

Visual Smalltalk Enterprise Language Reference 79 CHAPTER 2 Basic Building Blocks

Because of its well-defined ordering, all of its subclasses implement the equality (=) message in such a way that the answer is true if two IndexedCollections have the same class and size, and their corresponding elements answer true for the equality message. Class FixedSizeCollection Class FixedSizeCollection is a subclass of class IndexedCollection. It is an abstract class to provide common protocol for its subclasses that include: Array, ByteArray, Interval, String, DoubleByteString, Symbol, and DoubleByteSymbol. These subclasses represent collections with a fixed range of integer indices as external keys. Because these subclasses have fixed sizes, they cannot respond to the add: message. The instance creation message new: is subtly different when applied to a fixed-size collection compared to a variable one. The following message: (Array new: 5) size evaluates to 5, while (OrderedCollection new: 5) size evaluates to 0. When message new: is sent to class Array, the new instance is created with elements initialized to nil. When the message is sent to a variable-size collection, such as OrderedCollection, the new instance is created with space allocated, but is logically empty. The elements of an Array can be any objects. An element of a ByteArray must be a SmallInteger in the range of 0 to 255. The elements of a String or Symbol are characters. Symbols are guaranteed to be unique. An Interval represents a finite arithmetic progression. Its elements can be any kind of number: integer, floating point, or fraction. Although Interval contains all the numbers within a specified range and with a specified increment between each number, it is represented concisely with only three instance variables: beginning, end, and increment. Its elements are regenerated upon access rather than stored in the instance. To create an instance, the two Interval class messages, from:to: and from:to:by:, are used. Class Number also provides some shorthand messages, to: and to:by:, to create new Intervals.

80 Visual Smalltalk Enterprise Language Reference Collection Classes

Class OrderedCollection An OrderedCollection is ordered by the sequence in which objects are added to it and removed from it. It is like a dynamic array, except that it can be expanded on both ends. To facilitate this feature, messages are provided to add, remove, and access both the beginning and end. The add: message defined in class Collection is implemented to be like addLast:. Other messages enable you to access, add, or remove an object in the middle by specifying its preceding or succeeding object. OrderedCollections can act as stacks or queues. Operations to a stack are typically “last-in, first-out” (LIFO). Following is a comparison of terminology:

Typical Stack Vocabulary OrderedCollection Message push newElement addLast: newObject pop removeLast top last empty isEmpty

Operations to a queue are typically “first-in, first-out” (FIFO):

Typical Queue Vocabulary OrderedCollection Message add newElement addLast: newObject delete removeFirst front first empty isEmpty

Queues grow on one end and shrink on the other. When space is exhausted on the growing end, an OrderedCollection always checks the shrinking end. If there is enough space, it shifts the entire collection toward the shrinking end to make room for growing at the other end. If there is not enough space, it will allocate a larger space and copy the original collection to the new space. Growable collections do not shrink automatically.

Visual Smalltalk Enterprise Language Reference 81 CHAPTER 2 Basic Building Blocks

Class SortedCollection SortedCollections are ordered according to a two-argument block called the sort block. The sort block is used to determine whether two elements are correctly sorted relative to each other. Because the position of each element is dictated by the sort block, messages such as addLast: are disallowed. Message add: newObject, however, will insert the newObject into the sorted position according to the sort block. There are five ways to create a new instance: SortedCollection new SortedCollection new: 10 SortedCollection sortBlock: [ :a :b | a > b ] anyCollection asSortedCollection anyCollection asSortedCollection: [ :a :b | a > b] A sort block can be as complex as desired, but the last expression in the block must evaluate to either true or false. For example, the following sort block assumes that strings are being compared. It sorts the strings based on the number of unique vowels. [ :a :b | (a asLowerCase select: [ :c | c isVowel ] ) asSet size <= (b asLowerCase select: [ :c | c isVowel ] ) asSet size ] When the sort block is not specified at creation time, the following default sort block is used: [:a :b | a<= b] The sort block can also be changed any time by sending the message sortBlock: newBlock to a SortedCollection, which automatically resorts the whole collection according to the newBlock. Stream Classes The Stream classes are used for accessing files, devices, and internal objects as sequences of characters or other objects. Streams have an internal record of their current position. Streams also have access messages that get or put the next object at the current position and advance the stream’s position by one. Messages are defined for changing the stream position so that random access is possible.

82 Visual Smalltalk Enterprise Language Reference Stream Classes

This section describes the purposes of and the protocol shared among the Stream hierarchy classes. For a complete specification of each class, refer to the Encyclopedia of Classes. Streams are frequently used for scanning input and writing edited output. The key to the following sample implementation of printString, for class String, is that an instance of class WriteStream automatically grows to contain all the characters written to it and responds to the message contents by returning a string containing all of its characters. printString | character inputStream outputStream | inputStream := ReadStream on: self. outputStream := WriteStream on: (String new: self size + 2). outputStream nextPut: $'. [inputStream atEnd] whileFalse: [ character := inputStream next. outputStream nextPut: character. character == $' ifTrue: [outputStream nextPut: $'] ]. outputStream nextPut: $'. ^outputStream contents This example illustrates several Stream messages. Instances of classes ReadStream and WriteStream are created with the on: message with a string as the argument. Both streams are positioned at the first character. Note that in creating the WriteStream instance, space is provided for the containing quotes but not for interior paired quotes. If interior quotes exist, the String object affected by the WriteStream will automatically be enlarged. Characters are written to the WriteStream with the message nextPut:. The character to write is the argument. The end of a ReadStream is detected with the atEnd message. If there is a character at the current position, atEnd returns false; otherwise it returns true. A character is read from the ReadStream with the message next. Note that sending the message next to a ReadStream that is positioned at the end will result in a walkback. All characters in a WriteStream are returned as a string in answer to the contents message.

Visual Smalltalk Enterprise Language Reference 83 CHAPTER 2 Basic Building Blocks

Accessing Protocol The above information is summarized in the following protocol:

Protocol Explanation atEnd Answer true if stream is at the end, else answer false. contents Answer the collection of objects that is being streamed over. next Answer the next object in the receiver stream and advance the position by one. nextPut: anObject Write anObject at the current position. Answer anObject.

Positioning and Reading Protocol Some of the Stream positioning protocol is as follows:

Protocol Explanation atEnd Return true if the current position of the receiver is at the end of the stream (that is, beyond the last object). position Answer an integer representing the stream’s position. The position at the beginning of the stream is zero. position: anInteger Set the stream position to anInteger. Report an error if anInteger is beyond the end of the stream. reset Set the stream’s position to zero. skip: anInteger Add anInteger (which may be negative) to the stream’s position. skipSeparators Set the position of the receiver past any separator characters (space, tab, carriage return, line feed, or form feed).

Some Stream reading protocol follows:

Protocol Explanation do: aBlock Proceed through the stream from the current position to the end, evaluating aBlock with each element of the stream as the block argument. isEmpty Answer true if the stream contains no elements. Otherwise, answer false. next: anInteger Answer a collection of the next anInteger elements of the stream. Advance the stream position by anInteger. peek Answer the next element in the stream without advancing the stream position. Answer nil if at end of stream.

84 Visual Smalltalk Enterprise Language Reference Stream Classes

Protocol Explanation peekFor: anObject Answer true and advance the stream position if the next object in the stream equals anObject. Otherwise, answer false and leave the stream position unchanged. skipTo: anObject Set the stream position beyond the next occurrence of anObject in the stream or, if none, at the end of the stream. Answer true if there was an occurrence. Otherwise, answer false. upTo: anObject Answer a collection of objects starting at the current stream position and up to but not including the next object that equals anObject and advance the stream position beyond the object that equals anObject. If anObject is not in the stream, answer up to the end of the stream and set the stream position to the end.

The following example illustrates positioning and reading protocol using a stream on an array of symbols. First, the stream is created and assigned to the variable Colors. Then, a series of messages is sent to the stream Colors. The result of each message is shown below. Colors := ReadStream on: #(red blue green yellow pink cyan magenta brown).

Expression Answer

Colors isEmpty false Colors next red Colors next: 3 (blue green yellow) Colors peek pink Colors peekFor: #blue false Colors upTo: #magenta (pink cyan) Colors skip: -4 a ReadStream (not executed for its return value)

Colors position 3 Colors skipTo: #pink true Colors upTo: #red (cyan magenta brown)

Visual Smalltalk Enterprise Language Reference 85 CHAPTER 2 Basic Building Blocks

Writing Protocol Some additional Stream writing protocol follows:

Protocol Explanation cr Write a line-terminating character to the stream. next: anInteger Write anObject to the stream the anInteger number of times. put: anObject Answer anObject. nextPut: anObject Write anObject given as the argument to the receiver stream. Return the object that was written. nextPutAll: aCollection Write the elements of aCollection to the stream. Answer aCollection. space Write a space character to the stream. tab Write a tab character to the stream.

All objects understand the message printOn: with a stream as the argument. This message produces a character description of the receiver object on the argument stream. For example, the following is a typical implementation of the printOn: message: printOn: aStream "Append the ASCII representation of the receiver to aStream." leftTop printOn: aStream. aStream nextPutAll: ' rightBottom: '. rightBottom printOn: aStream where the printOn: message is sent to the corner left and right points and the message nextPutAll: is sent to its stream argument. An example of printing a rectangle is: Display boundingBox printOn: Transcript which writes the following in the Transcript window if you are running on a VGA screen: 0 @ 0 rightBottom: 640 @ 480

86 Visual Smalltalk Enterprise Language Reference File System Interface Classes

File System Interface Classes Class FileSystemEntity provides the primary high-level interface to the host file system. Classes File and Directory are included in the FileSystemEntity hierarchy. Instances of the class File represent a file, real or potential, on the file system. Class Directory provides access to storage devices and their hierarchical directories used to store files. Files File objects are created by sending a message to class File, specifying a partial or complete path name, or by sending a message to an instance of class Directory specifying a particular file to access in that directory. Here are some examples of messages to class File: File fromPath: 'CHAPTER.1' File fromPath: 'TUTORIAL\CHAPTER.1' File fromPath: 'C:\VSEW31\TUTORIAL\CHAPTER.1' The first creates a File object for CHAPTER.1 in the current directory. The second creates a File object for CHAPTER.1 in the TUTORIAL subdirectory of the current directory. The third creates a File object, specifying the full disk and directory path name. These messages do not open the files. The global variable Disk, an instance of Directory, holds the current directory path name and is used to complete an incomplete path, as in the examples above. You can create a File instance by sending one of the following messages to Disk or any other Directory object. These messages do not accept path names in the arguments, only a file name: Disk fileNamed: 'chapter.1' Disk newFileNamed: 'JunkFile' Disk existingFileNamed: 'MustExist' The newFileNamed: message succeeds only if the file named does not exist, and creates the file when opened. The existingFileNamed: message succeeds only if the named file does exist. The fileNamed: message succeeds in either case, and creates the file when opened if it does not exist already.

Visual Smalltalk Enterprise Language Reference 87 CHAPTER 2 Basic Building Blocks

Opening and Accessing Files Reading and writing to disk files is generally done using file streams. Sending readStream or writeStream to an instance of File creates a FileStream instance opened on the file with read or read/write access, respectively. For example, to open a file for read access, use: (File fromPath: 'FILENAME.EXT') readStream The readStream message requires that the file exist before opening. The writeStream message, on the other hand, creates the file if it does not exist already. Once the file is opened, you read from and write to the file using the usual stream protocols. The operating system typically buffers the data you write on a file stream, rather than writing it to disk as you write it. You can force the data to be written to disk by flushing the stream buffer: stream flush The buffer is also flushed just before closing the file: stream close File streams recognize two different formats for end of line, the carriage return/line feed pair (Cr-Lf) used by DOS, Microsoft Windows, and OS/2, and the single line feed (Lf) used by UNIX 4. When a file stream is opened, the beginning of the file is scanned to determine which format applies. New files are created using the host format (Cr-Lf). The following three messages let you test and change the line ending format for a file. stream lineDelimiter "Answers Cr or Lf" stream lineDelimiter: Lf "Change to Lf only format" stream lineDelimiter: Cr "Change to Cr-Lf pair format" Putting all of the above together, here is a program that converts text files from Cr-Lf to Lf format:

88 Visual Smalltalk Enterprise Language Reference File System Interface Classes

"Convert a file from Windows (Cr-Lf) format to Unix (Lf) format." | input output | input := (Disk fileNamed: 'textfile.in') readStream. output := (Disk newFileNamed: 'unixfile.out') writeStream. output lineDelimiter: Lf. [input atEnd] whileFalse: [output nextPutAll: input nextLine; cr]. input close. output close Directories The class Directory provides access to the host file system. The global variable Disk contains the device and directory path of the current directory, initially the directory from which you started Visual Smalltalk. You can create new Directory objects using the following messages: myDir := Directory fromPath: 'C:\DirName' anotherDir := ( Directory fromPath: '\' ) drive: $C Note that creating a Directory object does not create a directory on the disk drive itself. To create a new directory on the disk, send the message create to a Directory object with the proper drive and path name, as in: myDir exists ifFalse: [ myDir create]. Directory objects understand messages for listing their subdirectories and files, for creating new files and subdirectories, and more. See the Encyclopedia of Classes for more details. File Association On Microsoft Windows platforms, tthis extra implements a simple interface to the operating system File Association feature (find, execute). The file-in adds the class ShellDLL as a subclass of DynamicLinkLibrary, and adds methods to the File class. User Interface File Association allows you to use the file name extension to associate groups of files with an application. In File Manager, when the user selects a file, the program associated with that type

Visual Smalltalk Enterprise Language Reference 89 CHAPTER 2 Basic Building Blocks

of file is invoked, and the file is loaded into memory in a single operation. The process is functionally the same as loading the program and then opening the file. File associations are stored in the Registration Database and in the win.ini initialization file. Installation Partial support for the file association feature is included in the base image, but full functionality is optionally installable. To install full support, select File Associations in the Service Manager. Programming Interface The following methods are the major File Association messages: execute: Executes the identified file (an .EXE or .PIF file). This is a File method. To run a batch file, specify: command.com/c filename.bat findExecutable: Answers the name of the executable file for which an association exists for the identified file. shellExecute:operation: Opens or prints the identified file using the program associated with the file in the Registration Database. shellOpen: Opens the identified file using the program associated with that file in the Registration Database. shellPrint: Prints the identified file using the program associated with that file in the Registration Database. For example, the following message returns the name of the program associated with the file MYFILE.TXT: File findExecutable: ( File fullPathName: 'myfile.txt' ).

90 Visual Smalltalk Enterprise Language Reference Pattern

The shellOpen and shellPrint messages invoke the program associated with the identified file. When you use shellOpen, the program simply opens the file. In contrast, when you use shellPrint, the associated program opens and prints the file. File shellOpen: ( File fullPathName: 'myfile.txt' ). File shellPrint: ( File fullPathName: 'myfile.txt' ). Use the execute: message to invoke an application, or run a batch file or .PIF file. File execute: 'notepad.exe ', ( File fullPathName: 'myfile.txt' ). File execute: 'command.com /c mybat.bat'. File execute: 'mypif.pif'. Pattern The Pattern class provides support for doing pattern matching. A pattern is created by sending the new: class message to Pattern, with the pattern specified by a String. The string may include the wild card character “*”, in which case the pattern is created as an instance of WildPattern. For example: Pattern new: 'Find this' creates an instance of Pattern, and: Pattern new: 'F*nd this' creates an instance of WildPattern. Instance methods match the pattern against another object, which can be any subclass of IndexedCollection. Depending on the message sent, the return value is a Boolean value or an index. There are two ways to do pattern matching. One is to include the the entire collection in the message to the pattern, such as: aPattern match: 'Any collection to be checked' This is the most efficient approach when there is only one matching collection.

Visual Smalltalk Enterprise Language Reference 91 CHAPTER 2 Basic Building Blocks

The other approach to iterate on a collection, evaluating each element for a match, and evaluating a block for each match. For example: |pattern collection classes className| classes := Set new. (pattern := Pattern new: 'Object*') matchBlock: [classes add: className]. collection := Object allClasses. collection do: [:word| className := word name asString. pattern reset. className do: [:i| pattern match: i ] ]. ^classes This approach is normally used when there are several matching collections. PropertyManager Intuitively, a property is an attribute, or a characteristic, or a quality of an object. In Visual Smalltalk, an object property is represented as a value associated with a name. The value can be one of the states of an object or can be derived from one or more states of an object. When we talk about a property, it usually means a public (not private) value of certain object. While it is common to store properties in instance variables, this in not necessary. A property value may be derived from variables, or may be stored as a return value in a method. The Visual Smalltalk property manager is a mechanism that provides uniform ways for accessing an object’s property values its property names. To make modifying properties easier and safer, the property manager also provides a means for editing and validating property values. The property manager is implemented in two main classes. PropertyManager is defined as a subclass of Dictionary. A property manager holds instances of subclasses of PropertyAccessors, each of which provides mechanisms for managing a kind of property. Object properties are, by default, stored in a weak keyed registry for efficient garbage collecting.

92 Visual Smalltalk Enterprise Language Reference PropertyManager

Accessing Properties The main messages for accessing properties are implemented in Object. These are: propertyAt: aPropertyName Answer the value of the receiver’s property identified by aPropertyName, or nil if none. propertyAt: aPropertyName put: aValue Set the value of the receiver’s property identified by aPropertyName to anObject. To set a property value for an object, send a message like this:: anObject propertyAt: #roger put: 'a hard worker' Similarly, to retrieve a value, send: anObject propertyAt: #roger

Visual Smalltalk Enterprise Language Reference 93

CHAPTER 3 The Graphics Model Overview Visual Smalltalk supports a wide range of graphics support, using both bitmapped and vector graphics models. Bitmapped graphics copy pixels from a source area to a destination area and simulate vector operations by continuously copying. That is, drawing a line is simulated by continuously copying from the source bitmap to the destination bitmap and moving the destination location 1 pixel towards the other end of the line between every copy. In comparison, vector operations are difficult to simulate. For example, bitmapped graphics normally can only rotate bitmaps in increments of 90 degrees, while vector graphics allows rotations at any angle. In Visual Smalltalk, a graphics medium can be anything that is capable of displaying or storing graphics. It can be a monitor screen, a printer, a plotter, a file, or a portion of computer memory. In addition, each window object is treated as a separate medium. Graphics tools are grouped under class GraphicsTool. It has several subclasses, each of which extends the functionality of its superclass: •A TextTool works like a typewriter and only displays characters. •A Pen is capable of not only typing but also drawing graphics. •A RecordingPen has all the capabilities of a TextTool and Pen and, in addition, is capable of recording graphics operations as subpictures and replaying them later to form the whole picture. RecordingPen instances are among the most prevalent graphics tools in the Visual Smalltalk system as this class encompass all the capabilities of its superclasses and adds a powerful “instant replay” facility.

Visual Smalltalk Enterprise Language Reference 95 CHAPTER 3 The Graphics Model

Multiple graphics tools can be associated with a single medium. A graphics tool can also be disassociated from its current medium and reassociated with a different medium. Therefore, you can first associate a graphics tool with a window, compose your picture interactively and later reassociate it with a graphics printer to get a final hard copy of the picture. Each graphics tool has an instance variable called deviceContext which serves as a bridge to the operating system’s graphics interface. Under Windows, this graphics interface is the Graphics Device Interface (GDI). Usually GDI functions are accessed by sending a message to global variable GDILibrary (an instance of GDIDLL) with deviceContext as the first argument. Several demonstration classes for working and using graphics, including animation, are provided in the Graphics Demo, which is installable in the Service Manager. The Coordinate System In order for the graphics tool to address the pixels on the device, there must be a coordinate system imposed on the device. Visual Smalltalk supports the coordinate system native to the operating system platform to maintain host compatibility. This system is different between OS/2 and Windows operating systems. In the Windows coordinate system, the upper left corner of a pane or window is the origin (0,0), with the y coordinate increasing toward the bottom of the screen. In the OS/2 coordinate system, the lower left corner of a pane or window is the origin (0,0), with the y coordinate increasing toward the top of the screen. These two coordinate systems are illustrated in figure 3-1.

Figure 3-1: The Windows and OS/2 Coordinate Systems Windows OS/2 (0,0) +x

+y

+y

(0,0) +x

96 Visual Smalltalk Enterprise Language Reference The Coordinate System

Coordinate System Independence To increase portability between operating systems that use different coordinate systems, Visual Smalltalk provides a coordinate-system independent protocol in classes Point, Rectangle, and Number. The protocol allows you to use coordinates in a way that does not depend on the particular underlying coordinate system. For example, you send a rectangle messages such as leftTop and rightBottom to obtain its corner points, rather than using origin and corner. For doing arithmetic on screen locations, you send a number or a point message such as up: and down:, rather than using + and -. You compare two points by sending messages such as isLeftAndAbove: instead of using < and >. If you need to keep your program independent of the coordinate system, select your messages carefully. Not all messages are coordinate system independent. Also, if you specify coordinates in the argument of a message, you may lose system independence. Setting Graphics Display Units To maintain device independence, Windows systems use GDI to create output in a logical space and map it to the display. The mapping mode defines the relationship between units in the logical space and pixels on a device. The units of the coordinate system are selectable by using the GraphicsTool method setMapMode:. The available choices depend on the graphics interface. For GDI, they are as follows:

Mapping Mode Description MmAnisotropic Maps one logical unit to an arbitrary physical unit. The x-axis and y-axis are arbitrarily scaled. MmHienglish Maps one logical unit to 0.001 inch. The positive y-axis extends upward. MmHimetric Maps one logical unit to 0.01 millimeter. The positive y-axis extends upward. MmIsotropic Maps one logical unit to an arbitrary physical unit. One unit along the x-axis is always equal to one unit along the y-axis. MmLoenglish Maps one logical unit to 0.01 inch. The positive y-axis extends upward. MmLometric Maps one logical unit to 0.1 millimeter. The positive y-axis extends upward.

Visual Smalltalk Enterprise Language Reference 97 CHAPTER 3 The Graphics Model

Mapping Mode Description MmText Maps one logical unit to one pixel. The positive y-axis extends downward. MmTwips Maps one logical unit to 1/1440 inch (1/20 of a point; a point is 1/72 inch). The positive y-axis extends upward.

Note that these mapping modes are the symbolic names of variables in the pool OperatingSystemConstants. Graphic Classes The following classes are defined to describe locations and areas in the selected units of the coordinate system. •Point • Rectangle •Number Point A point refers to a position within a two-dimensional space. It has two instance variables: x, the horizontal coordinate, and y, the vertical coordinate. The most efficient way of creating a point is by sending the binary message @. For example, the expression: 5 @ 10 creates a point with an x coordinate of 5 and a y coordinate of 10. The first integer (the receiver) is the x coordinate and the second integer (the argument) is the y coordinate. The x: and y: messages alter the coordinates of a point, while the x and y messages retrieve these coordinate. For example:

Expression Result (1 @ 100) x 1 (1 @ 100) y 100 (1 @ 100) x: 50 50 @ 100 (1 @ 100) y: 50 1 @ 50

98 Visual Smalltalk Enterprise Language Reference Graphic Classes

Comparing Points To compare points, use these messages: isLeftAndAbove: aPoint isLeftAndBelow: aPoint isRightAndAbove: aPoint isRightAndBelow: aPoint between: aPoint and: aPoint For example:

Expression Result Windows OS/2

(1 @ 50) isLeftAndAbove: (50 @ 100) true false (1 @ 50) isLeftAndBelow: (50 @ 100) false true (1 @ 50) isRightAndAbove: (50 @ 100) false (1 @ 50) isRightAndBelow: (50 @ 100) false (1 @ 200) between: (0 @ 200) and: (2 @ 200) true

These messages compare two point positions and answer the point at the requested position:

Expression Result

(1 @ 100) leftMostAndHighest: (50 @ 100) 1 @ 100 (1 @ 100) leftMostAndLowest: (50 @ 100) 1 @ 100 (1 @ 100) rightMostAndHighest: (50 @ 100) 50 @ 100 (1 @ 100) rightMostAndLowest: (50 @ 100) 50 @ 100

The following messages compare numbers, but are useful for comparing point positions using the values of x and y coordinate values: isBelow: aNumber isLeft: aNumber isBelowEqual: aNumber isLeftEqual: aNumber isAbove: aNumber isRight: aNumber isAboveEqual: aNumber isRightEqual: aNumber To find the smallest or largest number, use:

Visual Smalltalk Enterprise Language Reference 99 CHAPTER 3 The Graphics Model

lowerOf: leftMost: higherOf: rightMost: Point Arithmetic Arithmetic can be performed on a point with either a point or a number (as a scalar) argument. To perform point arithmetic, use the messages that answer a point: up: aNumber down: aNumber left: aNumber right: aNumber leftAndDown: aPoint leftAndUp: aPoint rightAndDown: aPoint rightAndUp: aPoint For example:

Expression Result Windows OS/2

(1 @ 100) up: 9 1 @ 91 1 @ 109 (1 @ 100) down: 9 1 @ 109 1 @ 91 (1 @ 100) left: 9 -8 @ 100 -8 @ 100 (1 @ 100) right: 9 10 @ 100 10 @ 100 (1 @ 100) leftAndDown: (50 @ 100) -49 @ 200 -49 @ 0 (1 @ 100) leftAndUp: (50 @ 100) -49 @ 0 -49 @ 200 (1 @ 100) rightAndDown: (50 @ 100) 51 @ 200 51 @ 0

(1 @ 100) rightAndUp: (50 @ 100) 51 @ 0 51 @ 200

NOTE: In order to support IBM’s Smalltalk Common Base Specification, leftAndDown:, leftAndUp:, rightAndDown:, and rightAndUp: are also supported with the names transposed. For example, topLeft: instead of leftTop:.

100 Visual Smalltalk Enterprise Language Reference Graphic Classes

The following additional messages perform useful functions on points:

Expression Result (1 @ 10) * (3 @ 2) 3 @ 20 (1 @ 10) // 2 0 @ 5 (-2 @ -3) abs 2 @ 3 (2 @ 3) negated -2 @ -3 (2 @ 4) dotProduct: (5 @ 6) 34 (2 @ 4) transpose 4 @ 2

dotProduct: answers the sum of the product of the x coordinates and the product of the y coordinates of two points. Rectangle A Rectangle is a rectangular area in the coordinate system. It is defined by two points that represent diagonally opposed vertices of the rectangle. You can create a Rectangle with class messages or by sending messages to a Point instance. To specify an opposite corner, use these messages: rightBottom: aPoint rightTop: aPoint To define a rectangle by specifying its extent, or size relative to the receiver point, use these messages: extentFromLeftTop: aPoint extentFromLeftBottom: aPoint For example, try evaluating: (100 @ 100) extentFromLeftTop: (100 @ 40) You can also create a rectangle with these Rectangle class messages: leftTop: leftTopPoint rightBottom: rightBottomPoint leftBottom: leftBottomPoint rightTop: rightTopPoint

Visual Smalltalk Enterprise Language Reference 101 CHAPTER 3 The Graphics Model

NOTE: Avoid specifying a rectangle with bottom value below the top value (relative to the platform coordinate system), or with a left value larger than the right value. Visual Smalltalk allows you to specify such values, but the results can be unpredictable.

A Rectangle instance includes the points within the defined rectangle, including points in the top and left borders but excluding points in the bottom and right borders. For example: 2 @ 3 rightBottom: 5 @ 5 “Windows” 2 @ 5 rightBottom: 5 @ 3 “OS/2” contains 6 points, 3 horizontal and 2 vertical. To obtain a rectangle’s width and height use the width and height messages: | myRect | myRect := (100 @ 100) rightBottom: (200 @ 140). “use rightBottom: (200 @ 60) on OS/2” myRect width. myRect height. To illustrate the Rectangle instance messages, consider these rectangles Box1 and Box2: “Windows” Box1 := 20 @ 100 rightTop: 150 @ 0. Box2 := 70 @ 120 rightTop: 170 @ 80. “OS/2” Box1 := 20 @ 0 rightTop: 150 @ 100. Box2 := 70 @ 80 rightTop: 170 @ 120.

Expression Result Windows OS/2

Box1 top 0 100 Box1 bottom 100 0 Box2 left 70 70 Box1 right 150 150 Box1 center 85 @ 50 85 @ 50 Box1 width 130 130 Box1 height 100 100

102 Visual Smalltalk Enterprise Language Reference GraphicsMedium Classes

Expression Result Windows OS/2 Box1 leftBottom 20 @ 100 20 @ 0 Box1 rightTop 150 @ 0 150 @ 100 Box1 containsPoint: 50 @ 50 true true Box1 expandBy: 10 10 @ -10 rightBottom: 10 @ 110 rightBottom: 160 @ 110 160 @ -10 Box2 insetBy: 10 80 @ 90 rightBottom: 80 @ 110 rightBottom: 160 @ 110 160 @ 90 Box1 intersect: Box2 70 @ 80 rightBottom: 70 @ 100 rightBottom: 150 @ 100 150 @ 80 Box1 merge: Box2 20 @ 0 rightBottom: 20 @ 120 rightBottom: 170 @ 120 170 @ 0 Box1 translateBy: 10 @ 10 30 @ 10 rightBottom: 30 @ 110 rightBottom: 160 @ 110 160 @ 10

The following two expressions modify Box1 and Box2:

Expression Result Windows OS/2 Box1 moveBy: 10 @ 10 30 @ 10 rightBottom: 30 @ 110 rightBottom: 160 @ 110 160 @ 10 Box2 moveTo: Box1 leftBottom 30 @ 110 rightBottom: 30 @ 10 rightBottom: 130 @ 150 130 @ -30

GraphicsMedium Classes A graphics medium is like a piece of paper used to display or store drawings created by graphics tools. In this category, GraphicsMedium is the top class, an abstract class which should never have any instances. Classes Printer and Screen should have one instance for each physical device. For example, Printer can have instances for each configured printer. Global variable Display is the instance for your primary monitor screen. Classes Bitmap and StoredPicture, however, can have as many instances as needed.

Visual Smalltalk Enterprise Language Reference 103 CHAPTER 3 The Graphics Model

Class Window and its subclasses are also graphics media. Even though they are not implemented as subclasses of GraphicsMedium, they support the same common protocol. GraphicsMedium GraphicsMedium is an abstract class which contains the common code for all its subclasses. It has two instance variables: graphicsTool contains the graphics tool associated with the medium, and deviceContext contains the device context of the medium. The medium description usually includes device specific information and device driver code for running the medium. Following is the common protocol for all media: extent Answer a point representing the width and height of the medium page which is screen, printer page, or bitmap. pen Answer the GraphicsTool that is currently associated with the receiver medium. Bitmap A bitmap is an array of bits organized into rows and columns in which the bits correspond to the pixels on the associated display medium. A bitmap can represent a monochrome or colored image. For a monochrome bitmap, each bit in the bitmap corresponds to a pixel on the display medium. For colored bitmap, multiple bits are required to represent a color pixel. The class Bitmap provides the protocol to create and display a bitmap. The class Bitmap has the following instance variables: archive Used as a buffer to save the bits of a bitmap when an image is saved. bitmapHandle Contains a handle for the bitmap when an image is active and the bits are in memory. bitmapInfo Contains a structure that describes the bitmap width, height, bit count, and bit planes. palette The palette of a bitmap determines the interpretation of the bits in the bitmap data as colors. That is, the palette maps

104 Visual Smalltalk Enterprise Language Reference GraphicsMedium Classes

the color indices that are present in the bitmap data into color values. In this way, a palette allows bitmap data to be represented more compactly than by having each pixel contain an RGB color value. Monochrome Bitmaps For a monochrome bitmap, each bit in the bitmap corresponds to a pixel when displayed on the screen. For example, to make a new (100 by 100) monochrome bitmap, use Bitmap width: 100 height: 100 or Bitmap extent: 100 @ 100 Color Bitmaps For a multi-colored bitmap, more than one bit is needed to represent a colored pixel on the screen. There are two ways to implement color bitmaps. One way to represent color in your bitmaps is to have multiple planes. Each plane consists of consecutive bits in memory. The bits in the same position of each plane are taken together to form the color for the pixel in that position. In this way, a sixteen color bitmap needs four planes. The other way to implement a color bitmap is to have a consecutive number of bits represent one pixel. For a sixteen color bitmap, each pixel is represented by four consecutive bits. For example, to make a multi-color bitmap, you usually use Bitmap screenWidth: 100 height: 100 or Bitmap screenExtent: 100 @ 100 These last two expressions allocate a bitmap that is compatible with the screen format, either with planes or consecutive bit counts. All four expressions above automatically create a Pen associated with the Bitmap instance. This Pen is stored in the instance variable graphicsTool and can be accessed by the message pen. For example,

Visual Smalltalk Enterprise Language Reference 105 CHAPTER 3 The Graphics Model

| aBitmap | aBitmap := (Bitmap screenWidth: 100 height: 100). aBitmap pen erase; place: 20 @ 20; box: 80 @ 80. aBitmap displayAt: 0 @ 0 with: Display pen. aBitmap release draws a box on a 100 by 100 bitmap and displays it in the upper left corner of the screen on Windows, and the lower left corner on OS/2. Note that the last line releases the memory associated with the bitmap. 256-Color Bitmaps In Windows, any application can change the default system palette. Consequently, it is necessary for a bitmap to have its own palette and use it when the bitmap is displayed. The palette is saved in the instance variable palette, defined by the Bitmap class. This instance variable contains the color palette for the bitmap. The class variable DefaultPalette contains a handle to the default system palette. The default system palette is selected into the bitmap's device context when it is released. StoredPicture StoredPicture is used to record a sequence of graphic operations. The resulting object is commonly called a metafile. Once recorded, the metafile can be written to an external file for replaying later. To replay a sequence, you load the file into a new metafile, connect it to a graphic tool, and send the drawUsing: message. The following sequence shows how to create and save a stored picture metafile:

106 Visual Smalltalk Enterprise Language Reference GraphicsMedium Classes

| meta | meta := StoredPicture new. meta startRecording. meta "Draw to the metafile." pen place: 100 @ 100; box: 200 @ 200. "Many more instructions can be added" meta stopRecording. meta outputToFile: 'test.met'. "Save to disk." meta release. "Release the metafile memory." The following shows how to use a stored picture once it has been created and saved: | meta pane | meta := StoredPicture fromFile: 'test.met'. "Load the metafile from disk." TopPane new "Open a graphics pane" addSubpane: (pane := GraphPane new); label: 'Stored Picture Display'; openWindow. meta drawUsing: pane pen. "Draw the picture using the graph pane pen." meta release "Release the memory" Printer Unlike the outputToPrinter method in class String (which prints strings in strictly character mode), class Printer allows graphics to be printed on paper in a manner consistent with Windows display media handling. Thus you can use a RecordingPen to draw graphics in a window and then reassociate the pen with a printer to replay its graphics on the printer with a “what you see (in the window) is what you get (on paper)” output. Printer output can be done in either landscape or portrait mode depending on the selection made through the Print Setup dialog box. When you draw graphics, keep in mind that the coordinate origin (0, 0) is in the upper left corner of the page. When you output hard copies you normally output them to a printer spooler queue. The connection between the spooler queue and the physical printer is managed by the operating system. You can reconfigure this spooling queue and printer connection through Print Manager. The following is an example of using your default printer to print graphics:

Visual Smalltalk Enterprise Language Reference 107 CHAPTER 3 The Graphics Model

| printer | printer := Printer new. “Create a printer medium using default printer" printer startPrintJob. "Connect the default graphics tool to the printer and initialize it" printer pen "Use the default graphics tool to draw" place: 100 @ 100; "Set initial pen position" box: 300 @ 300. "Draw a box" printer endPrintJob "Finish the job and release printer" If you have a RecordingPen which has recorded some graphics drawings on some other device, such as in a Turtle graphics window, you can print the recorded graphics on your default printer simply by: Printer printWith: aRecordingPen Screen Class Screen makes the monitor screen available for graphics drawing. The global variable Display is an instance of the primary screen and it is always connected to a default graphics tool throughout the Visual Smalltalk session. For example, if you want to blank out the whole screen and draw a box, simply execute: Display pen "use the default graphics tool of Display" erase; "paint the screen in default background color" place: 200 @ 200; box: 300 @ 300. You rarely draw anything using Display since all drawing should be done inside windows. However, Display can be used as a convenient scratch pad to test uncertain graphics operations. Another use of Display pen is when you want to drag a figure from one window to another. Display is needed in this case because drawing to a window guarantees that you won’t be able to draw outside of the window whereas Display pen allows you to draw anywhere on the screen.

108 Visual Smalltalk Enterprise Language Reference Graphics Tool Classes

Window An instance of Window is physically a subdivision of Screen in the system model. Due to its importance and complexity, the Window class is implemented as a subclass directly under Object instead of under GraphicsMedium. Although it is not a subclass of GraphicsMedium, it possesses the same information as other media, namely, a deviceContext and a graphicsTool. All the common protocol in class GraphicsMedium is also supported by Window and its subclasses. Note that, unlike bitmaps, each window has its own device context. The complete description of Window is presented in chapter 5. Graphics Tool Classes Graphics tools are instruments used to draw graphics on various graphics media. Therefore, before you can use a GraphicsTool instance you have to first associate it with an instance of GraphicsMedium. For convenience, every time you create a new instance of a medium, a default graphics tool is created and associated with it. This default graphics tool is accessed by sending the message pen to the GraphicsMedium instance. For example: (Bitmap width: 100 height: 100) pen. Printer new pen. Display pen. When you use one of these pens to draw, the result is displayed on the associated medium. Of course you can always reassociate a pen with a different medium as long as the same graphics capabilities are supported. A graphics tool always has its instance variable graphicsMedium pointing to the associated medium. Conversely, the medium always has its instance variable graphicsTool pointing back to the associated graphics tool. GraphicsTool GraphicsTool is an abstract class which contains the common data and methods for its subclasses. It also contains the methods that implement bit block transfers (BitBlt-like operations). Following are the instance variables: backColor The background color used to fill the background of the display medium.

Visual Smalltalk Enterprise Language Reference 109 CHAPTER 3 The Graphics Model

deviceContext A handle connects to the system graphics interface which provides device-independent information. foreColor The foreground color used by the graphics tool to draw. graphicsMedium Contains the GraphicsMedium that is associated with the tool. height The height of the page medium. For a window, this is the height of the window. For a printer, this is the paper height. location The current location of the tool. logicalTool Contains a handle to a pen object. width The width of the page medium. For a window, this is the width of the window. For a printer, this is the paper width. Protocol for querying dimensions of the page medium associated with the graphics tool are: boundingBox A rectangle with origin (0, 0) and extent of the page medium. extent A point whose x is the width and y the height of the page medium. height The height of the page medium. width The width of the page medium. Sometimes you want your drawing to affect only a portion of the whole medium. If this smaller portion is a simple rectangle, you can use: aGraphicsTool execute: aBlock clipRect: aRectangle The Smalltalk code in aBlock is evaluated and any graphics generated from the evaluation is confined within aRectangle.

110 Visual Smalltalk Enterprise Language Reference Graphics Tool Classes

When you draw graphics, you can specify a mixing rule that tells the graphics interface how to combine the source pixels with the pattern pixels and the destination pixels. For graphics other then BitBlt, set the mixing rule by: aGraphicsTool setForegroundMode: mixConstant or aGraphicsTool setBackgroundMode: mixConstant where setForegroundMode: sets the foreground mixing rule, and setBackgroundMode: sets the background mixing rule. The mixConstant can be one of the following, as defined in pool dictionary GraphicsConstants:

mixConstant Value Effect Background

BackgroundMixOpaque Background is filled with the current background color before drawing. BackgroundMixTransparent Background remains untouched. Foreground

MixRuleCopyPen Drawing is done in current foreground color. MixRuleCopySurface Drawing has no foreground effect. MixRuleDefault Pixel is the pen color. MixRuleInvertPen Pixel is the inverse of the pen color. MixRuleInvertSurface Pixel is the inverse of the screen color. MixRuleNotOr Pixel is the inverse of the MixRuleOr color. MixRuleNotXor Pixel is the inverse of the MixRuleXor color. MixRuleOr Pixel is a combination of the pen color and the screen color (the final pixel = pen logically ORed with the screen pixel). MixRuleXor Pixel is a combination of the colors that are in the pen and in the screen, but not in both (the final pixel = pen exclusive ORed with the screen pixel).

Note that setting the mix rule does not affect the BitBlt operations which have their own ways of specifying the mix rules.

Visual Smalltalk Enterprise Language Reference 111 CHAPTER 3 The Graphics Model

When you want to copy graphics from one place to another, either on the same device or on different ones, BitBlt functions are the most efficient to use. In class GraphicsTool, BitBlt functions are encapsulated in the copy and fill methods so that you do not need to worry about the details. For example, Display pen copy: Display pen from: ( 0@ 0 extent: 100 @ 100) to: (200 @ 200 extent: 200 @ 200) copies from screen to screen via a BitBlt operation. Since the destination rectangle is larger than the source in this example, the result is magnified from the source. Note that BitBlt messages shouldn’t be used in a StoredPicture, since bitmaps are device-dependent. For example, you do not get WYSIWYG results when you print a StoredPicture that contains a bitmap. TextTool TextTool is used to draw characters. It works like a typewriter except that it inherits methods from GraphicsTool so that it can do region filling and block moves. A TextTool is normally used with windows such as ListPane and TextPane where general graphics drawing is not usually required. The following is an example of using a TextTool: | aWindow textTool | aWindow := TextWindow windowLabeled: 'TextTool Examples' frame: (100 @ 100 extent: 400 @ 200). aWindow nextPutAll: 'Hi';cr. "Display initial text." textTool := aWindow pane pen. "Access the TextTool." textTool place: 24 @ 16; "Set position." displayText: 'Welcome'. "Display string at position." textTool displayText: 'to' at: textTool location + (50 @ 30). "Down and right from location." textTool centerText: 'Visual Smalltalk' at: textTool extent // 2. "Display a string at center."

112 Visual Smalltalk Enterprise Language Reference Graphics Tool Classes

textTool lineDisplay: 'Windows' at: (textTool width - 60) @ (textTool height - 20). "In lower right corner and blank the rest of the line." Pen Class Pen inherits all the capabilities of TextTool. In addition, it provides a vector graphics drawing interface. In other words, you can position the pen to a desired place and then tell it to draw a line, a box, or some other graphical figure. Besides position, a Pen instance also maintains its direction, down state, pen width, and pen style. Direction is an integer and goes from 0 to 359 degrees clockwise. Direction only applies to the go: message. For example: aPen direction: 0; go: 100 draws a line from the current position eastward for 100 units. A direction of 90 degrees goes northward, and 270 degrees goes southward. On Windows platforms, the Pen can use either Microsoft Windows directions (positive values turn clockwise; direction: 90 is south) or OS/2 compatible directions (positive values turn counter-clockwise; direction: 90 is north). Visual Smalltalk uses OS/2 compatible directions are the default. The Pen method CompatibleDirection: sets the compatibility. If set to true, OS/2 compatibility is selected; if set to false, Windows compatibility is selected. Down state tells the pen whether or not to draw a line as it moves. When its down state is false, the pen does not draw the line. However, its position gets updated as if the drawing were performed as it moves. aPen down "Sets down state to true." aPen up "Sets down state to false." Pen width is the width of the pen tip or the width of the line it draws. You can use the setLineWidth: message to change the pen width. Pen operations are summarized in the following collection of simple examples. Line drawing is the most basic drawing performed with a pen:

Visual Smalltalk Enterprise Language Reference 113 CHAPTER 3 The Graphics Model

Display pen place: 0 @ 0; setLineWidth: 8; "Set line width to 8 units." north; turn: -45; go: 100; "Draw a diagonal line for 100 units." goto: Display extent // 2; "Draw another line from the end of the previous line to the center of the screen." box: Display extent // 4; "Draw a box." setLineWidth: 1 "Set line width to 1 unit." Arc drawing allows you to draw a partial arc, a full arc (that is, ellipse or circle), or a partial arc closed with a chord. The following draws a full circle centered on the screen: Display pen circle: 100 "Draw a circle with radius of 100 units." To define an ellipse, in addition to the current pen position as the center, you need two points: the end of the major axis and the end of the minor axis (with the current pen location at 0 @ 0): Display pen ellipse: 100 minor: 30 To draw a partial arc, you need to specify an extra point whose x coordinate is the starting angle and whose y coordinate is the sweeping angle. When you start Visual Smalltalk, note that the pen is initially at location 0 @ 0. Ensure that the pen is in a location where the partial arc will display, as shown in the following example: Display pen place: 100 @ 100; partialArc: 80 minor: 40 angles: (90 @ 180). RecordingPen RecordingPen supports all the capabilities of GraphicsTool, TextTool, and Pen. In addition, it can record the drawings in a graphics segment and later replay the segment. There are three ways to draw a segment: aPenRecorder retainPicture: aBlock aPenRecorder drawPicture: aBlock aPenRecorder drawRetainPicture: aBlock

114 Visual Smalltalk Enterprise Language Reference Graphics Tool Classes

Each of these expressions will execute aBlock which typically includes graphics operations to be recorded. A segment id is returned by each expression so that you can replay the segments selectively later on. The retainPicture: method records the picture without actually drawing it. The drawPicture: method draws the picture without recording it; therefore, it cannot be replayed. The drawRetainPicture: method both draws the picture and records it. The following is an example of drawing a triangle and then replaying it twice to make a star: Window turtleWindow: 'RecordingPen Examples'. Turtle drawRetainPicture: [ Turtle fill: (Color blue); home; mandala: 16 diameter: 250 ] Font Font contains information needed to use a font. A font can be fixed width or variable width (proportional). It can be a bitmap (image) font or an outline (vector) font. An outline font allows characters to be scaled to any arbitrary size. It also maintains higher quality when drawing magnified or bold characters. Create an instance of Font using new, followed by font specifications. For example: Font new faceName: 'Arial'; bold: ture; pointSize: 10; yourself. The Font class message allFonts answers a collection of all the fonts that the user has installed through the Control Panel. The characteristics of a font can be obtained by sending one of these messages to a Font object: basePoint Answer a point where the y-coordinate is the ascent of the font. charSize Answer a point, the x coordinate is the average width and the y coordinate is the largest height of characters in the font.

Visual Smalltalk Enterprise Language Reference 115 CHAPTER 3 The Graphics Model

charWidth: aCharacter Answer the width of aCharacter. descender Answer a positive integer as the maximum descender. faceName Answer the face name of the receiver. fixedWidth Answer true if the font is of fixed width, else answer false. height Answer the height of the font in pixels. isImage Answer true if the font is an image font, false if it is an outline font. pointSize Answer the size of the font in points. pointSize: anInteger graphicsMedium: aGraphicsMedium Sets the point size of the font for aGraphicsMedium. spaceWidth Answer the width of the space character. stringWidth: aString Return the pixel width of aString written in the receiver font. Colors A color model is a method for describing or classifing colors in terms of basic elements. Visual Smalltalk supports two color models: the Red-Green-Blue color mix model and the system color index model. The system color index specifies colors by the operating system index value. The RGB model specifies colors as a mix of red, greem and blue color components. Red, Green and Blue The RGB (Red, Green, Blue) color model mixes the additive primary colors red, green, and blue to create all other colors. This is the system color monitors use to display color. Red, green, and blue phosphors on the monitor are illuminated in varying proportions to produce the colors that you see.

116 Visual Smalltalk Enterprise Language Reference Colors

For example, a reddish color is obtained by illuminating the red phosphors significantly more in proportion to the green and blue phosphors. Raising the levels of green and blue then produces a lighter color, because the total amount of light issuing from the screen is now greater. In the RGB system, the origin of color space, (0,0,0) is black. White is located at (1,1,1). Cyan, Magenta and Yellow The CMY (cyan, magenta and yellow) color model mixes the subtractive primary colors, cyan, magenta and yellow, to create all other colors. This is the system color printers use to print color. Cyan, magenta, and yellow inks are mixed on paper, film, or other physical media, in varying proportions to produce the colors that you see. When colored pigments are combined, they produce a wide range of colors. When mixed in different proportions, three particular colors of pigment can form all other colors. Each of these colors reflects light within a limited range of wavelengths. When they are mixed, less light is reflected and the colors appear darker. Because mixing paints or inks subtracts light, these colors are the subtractive primaries. The system of mixing colored pigments is called the subtractive color system. The RGB color system specifies colors as a mixture of the three primaries, with any given color specified as a particular mix. If we assign each primary to a Cartesian axis, the entire color space can be illustrated as a cube, the RGB color cube (figure 3-2).

Visual Smalltalk Enterprise Language Reference 117

CHAPTER 3 The Graphics Model

index: Returns an instance of IndexedColor specified by an integer value. The actual color returned is determined by the system color indexes. Several class messages return standard colors. For example red Returns an instance of the color red. green Returns an instance of the color green. blue Returns an instance of the color blue. black Returns an instance of the color black. white Returns an instance of the color white. gray Returns an instance of the color gray halfway between black and white. Browse the Color class methods for other predefined colors. Instances of RGBColor respond to the instance messages red, green, and blue by returning that color component value. Converting between Color Models To get the equivalent IndexedColor value for an RGBColor instance, send the asInteger method: anRGBColor asInteger Indexed colors also respond to this message by returning their index value. Similarly, you can get the equivalent RGB mix component values for an IndexedColor instance by sending asRGBColor: anIndexedColor asRGBColor Setting Foreground and Background Colors The foreground and background color of a GraphicsTool can be set using these expressions: foreColor: aColor backColor: aColor The argument to these methods is an instance of class Color.

120 Visual Smalltalk Enterprise Language Reference CHAPTER Building a Graphical 4 User Interface Overview Modern interactive applications typically make extensive use of a graphical user interface (GUI). Visual Smalltalk makes it easy to build a GUI interface using the native operating system technology. The resulting application is highly portable to other operating system environments that have similar capabilities. The Visual Smalltalk Enterprise User’s Guide describes how to build a GUI using the PARTS Workbench and interface it to your Smalltalk application. Building the GUI in the workbench is the easiest, and the preferred method for building a user interface in Visual Smalltalk. Occassionally, however, you may need or prefer to build the interface directly in Smalltalk. This chapter describes the classes and methods available to do that. The basic GUI element is the window, which consists of the main window frame, title bar, menu bar, window panes (subwindows), and various controls. In Visual Smalltalk, all window, pane and other control objects are defined as subclasses of the Window class. This provides a uniform interface for assembling your GUI. To coordinate the application logic with the GUI, applications are built within an application framework. Visual Smalltalk provides two application frameworks, built around the ViewManager and ApplicationCoordinator classes. These frameworks are described in the next chapter. In this chapter we describe the GUI elements provided by the Window subclasses and how to assemble them into a window.

Visual Smalltalk Enterprise Language Reference 121 CHAPTER 4 Building a Graphical User Interface Window and Panes Visual Smalltalk provides the basic window building components in subclasses of Window. The two most important subclasses for building the GUI are TopPane and SubPane. Top Panes When building a view, you specify a top pane that serves as the main window for the view. TopPane provides common protocol for the top-level windows, except for dialog windows. It is responsible for creating the whole window and managing its subpanes. Subpanes are added to the top pane. MainWindow provides a few special methods used by the Application Coordinator framework. DialogTopPane is a subclass of TopPane, and provides common protocol for the top-level dialog windows. It is responsible for creating the whole window and for managing its subpanes. It receives all the system messages sent to the window as well as the ones sent to its component controls. Subpanes Class SubPane is an abstract class providing a common protocol for a large number of panes that you can include in your application. To include a subpane in a window, you send the addSubpane: message to either an instance of the top pane or to another subpane. The receiver becomes the parent of the new subpane. Based on the application’s requirements, the subpane definition can include a number of properties, including (these are all optional): • An owner, the default receiver of event handler messages. • Event handlers. Each subpane has a collection of events that it triggers. The view registers a handler for each event that it needs to respond to. For a list of events that each subpane class triggers, refer to the Encyclopedia of Classes, or evaluate using Inspect It: paneClassName eventsTriggered

122 Visual Smalltalk Enterprise Language Reference Window and Panes

• Accessor methods, for setting and retrieving the state of the pane. For example, various panes respond to these messages:

Method Description c ontents Answer the contents of the pane. c ontents: Set the contents of the pane. selec tion Answer the current selection. selec tion: Set the selection. setM enu : Set the menu for the pane.

• One or more update methods, such as update, update:, update:with:, which are invoked when the owner sends itself a changed:, changed:with:, or changed:with:with: message with the pane’s name and zero or more arguments. • A frame size specification, defining the area of the subpane relative to its parent. • A style, which determines some pane-specific characteristics, such as whether scroll bars are needed. There are five major subclasses of SubPane: C ontrolPane Subclasses providing wrappers for operating system native GUI controls G raph Pane A subpane for displaying graphics G rou pPane A subpane for containing other subpanes, so they can be handled as a group ListPane A Visual Smalltalk implementation of the List Box control TextPane A subpane to contain editable text

Examples of most subpane classes are available throughout the Visual Smalltalk class heirarchy and in the tutorial files. Sizing and Positioning Panes When you add a subpane, you must specify its size and location within its parent pane. There are three ways to specify this framing information; by sending either layoutFrame:, framingRatio:, or framingBlock: to the pane. In part the choice is a matter of preference, depending on the approach you find easier to understand. The choice is also affected by the sizing characteristics you want the subpane to have as its parent is resized.

Visual Smalltalk Enterprise Language Reference 123 CHAPTER 4 Building a Graphical User Interface

Whichever method you use, the framing information is used by the pane when it is created and whenever its window is resized. Framing information is always specified relative to the parent pane, the pane to which its defining addSubpane: message was sent. Layout Frame The message layoutFrame: takes as its argument an instance of either LayoutFrame or Rectangle. Instances of Rectangle are automatically converted to instances of LayoutFrame. LayoutFrames can be specified in several ways: • Specify a scaled rectangle. The rectangle is scaled relative to the parent using ratios. • Specify an inset value relative to the parent, in pixels. • Specify the position using both ratios and insets. Ratios scale the pane’s layout frame relative to its parent pane. The entire parent rectangle is given by two points: 0@0 is the top left corner, and 1@1 is the bottom right corner. To create an instance of LayoutFrame, use either the topLeftRatio: or bottomRightRatio: messages, specifying a point as the argument. By default, bottomRightRatio: assumes a top left ratio of 0@0. For example, the following line specifies a pane that takes up the entire area of its parent window: pane layoutFrame: (LayoutFrame bottomRightRatio: 1 @ 1) If you use topLeftRatio:, you also need to specify the bottom right ratio by sending bottomRightRatio: to the new instance (see the example below). You can modify instances of LayoutFrame using the messages topRatio:, bottomRatio:, leftRatio:, or rightRatio:. The bottom ratio must be greater than or equal to the top ratio, and the right ratio must be greater than or equal to the left ratio, or the scaled rectangle is not valid. After changing the frame size, send resizeWindow to the window to rescale the pane. You can also scale the frame by specifying inset values in pixels. Insets are specified by integer value arguments to the messages topInset:, bottomInset:, rightInset:, leftInset:, or inset:.

124 Visual Smalltalk Enterprise Language Reference Window and Panes

For example, try the following code builds the pane shown in figure 4-1: (LayoutFrame topLeftRatio: (2/5) @ (1/2) bottomRightRatio: 1 @ 1) rightInset: 10; bottomInset: 15. Figure 4-1: Layout frame with insets

1/2 ratio

1 ratio

2/5 ratio 10 inset

15 inset 1 ratio

Insets are usually specified relative to a rectangle, but you can specify a negative inset relative to a line or a point. For example, the following expression uses a negative inset to build a pane relative to a line instead of a rectangle. Figure 4-2 shows the resulting pane: (LayoutFrame topLeftRatio: (1/2) @ 0 bottomRightRatio: 1 @ 0) rightInset: 10; topInset: 20; bottomInset: -45.

Visual Smalltalk Enterprise Language Reference 125 CHAPTER 4 Building a Graphical User Interface

Figure 4-2: Layout frame with negative inset.

20

45 25 10 1/2 ratio

Framing Ratio The framingRatio: message takes a Rectangle as its argument, specifing the size and location of the subpane as a fraction of its parent pane. Its parent’s size is taken to be the unit rectangle given by 0 @ 0 extent: 1 @ 1. You specify the framing ratio as a rectangle with coordinates specified as fractional values between 0 and 1. The framing ratio is used to calculate the size of the subpane relative to the parent window’s rectangle. The pane grows and shrinks to keep the same size proportions relative to its parent pane’s size as the parent pane is resized. Figure 4-3 illustrates the unit rectangle. Here are several examples of Rectangle arguments.

Description Rectangle Argument

Entire parent rectangle Rectangle leftTopUnit extentFromLeftTop: 1 @ 1 Upper half Rectangle leftTopUnit extentFromLeftTop: (1 @ (1/2)) Lower half Rectangle leftBottomUnit extentFromLeftBottom: (1 @ (1/2)) Left half Rectangle leftTopUnit extentFromLeftTop: ((1/2) @ 1) Right half (Rectangle leftTopUnit right: (1/2)) extentFromLeftTop: ((1/2) @ 1)

126 Visual Smalltalk Enterprise Language Reference Window and Panes

Figure 4-3: FramingRatio Unit Rectangle

leftTopUnit rig h tTopUnit

leftB ottomUnit rig h tB ottomUnit

Description Rectangle Argument

Upper left quadrant Rectangle leftTopUnit extentFromLeftTop: ((1 @ 1) / 2) Upper right quadrant (Rectangle leftTopUnit right: (1/2)) extentFromLeftTop: ((1 @ 1) / 2) Lower left quadrant Rectangle leftBottomUnit extentFromLeftBottom: ((1 @ 1) / 2) Lower right quadrant (Rectangle leftBottomUnit right: (1/2)) extentFromLeftBottom: ((1 @ 1) / 2)

Framing Block The framingBlock: message dynamically computes the size and location of the subpane relative to its parent pane’s rectangle. The framingBlock: message takes a one-argument block as its argument. The argument for the framing block itself is the parent window’s rectangle (box in the examples below). The block must evaluate to a Rectangle that fits within the parent’s client area. The coordinates of the resulting rectangle define the size and position of the subpane within the parent rectangle. The rectangle can be either fixed-size or relative, according to the logic in the framing block.

Visual Smalltalk Enterprise Language Reference 127 CHAPTER 4 Building a Graphical User Interface

Some sample framing blocks are given below.

Description Block Argument Entire parent rectangle [:box | box] Upper half [:box | box leftTop extentFromLeftTop: (box width @ (box height // 2))] Right half [:box | (box leftTop right: (box width // 2)) extentFromLeftTop: ((box width // 2) @ box height)] Lower left quadrant [:box | box leftBottom extentFromLeftBottom: (box extent / 2)]

Framing blocks are useful for subpanes that have a fixed dimension. For example, say you have a subpane that is always exactly two lines of text tall, regardless of the size of the parent, and one-third of the parent’s width, centered horizontally in the middle third at the top of the parent. For this pane, you would provide the following framing block: [:box | (box leftTop right: (box width // 3)) extentFromLeftTop: ((box width // 3) @ (SysFontHeight * 2))] Navigating Between Panes Tabbing Tabbing provides the user an easy way to move between subpanes by pressing the TAB key. Any subpane that can have the input focus can be a tab stop. By default, every subpane that can be a tab stop is set to be a tab stop. To prevent a subpane from being a tab stop, you can send the message noTabStop to the subpane. The tab stop order is determined by the order in which the subpanes are added to the parent. Operating system behavior specifies that a radio button that is “on” is always a tab stop, and a radio button that is “off” is never a tab stop. Visual Smalltalk dynamically sets and clears the tab stop on a radio button, preserving operating system behavior. Tabbing can cross group pane boundaries, so you can tab into subpanes inside a group pane and out of them.

128 Visual Smalltalk Enterprise Language Reference Window and Panes

Since a text pane has other semantics for the Tab key, when in a text pane, to move the input focus to the next tab stop use Control-Tab instead. To move the input focus to the previous tab stop, use Shift-Tab. From a text pane, to move the input focus to the previous tab stop use the Control-Shift-Tab combination. Direction Keys You can navigate among the subpanes within a group by using the four direction keys. Similar to tabbing, the ordering is determined by the sequence in which the subpanes are added to their parent. Grouping is determined by sending the message startGroup to a subpane. Sending startGroup to a subpane ends one group that includes the previous subpane and starts a new group starting with the receiver. The grouping used for the direction keys is the same used to group radio buttons. Therefore, you need to send the message startGroup to the first radio button in each group and to the first subpane immediately following the last radio button of each group. If a subpane does not already have any meaning for the direction keys, all four can be used for navigating around the subpanes. In such a case, the left arrow and up arrow keys move the focus to the previous subpane in the group, and the right arrow and down arrow keys move to the next. If the focus is in the last subpane in a group, using the direction keys, the focus will move the first. If a subpane already has some meaning for two of the direction keys, those two will keep their meaning. The two that are not defined by the subpane itself will be used for chaining the focus to other subpanes. Since a text pane uses all four direction keys, the direction keys cannot be used to change the focus to other subpanes. Default Push Button A default push button triggers the clicked event when the user presses the Enter key in any subpane under the following conditions: • The subpane that has the input focus is not a TextPane, where the Enter key is interpreted as a new line. • The subpane that has the input focus is not another push button. When a push button that is not ordinarily the default

Visual Smalltalk Enterprise Language Reference 129 CHAPTER 4 Building a Graphical User Interface

push button gets the input focus, it in effect becomes the default push button. That is, if a button has the input focus and user presses the Enter key, the button containing the input focus will trigger the clicked event—not the original default push button. To make a button into the default push button, send it the message defaultPushButton before opening the window. You can have only one default push button per main window. Visually, a default push button has a thicker border than an ordinary push button. If the user places the focus in a button other than the original default push button, the new button will have a thick border and the original default push button will have an ordinary border. When the input focus moves to another subpane other than a push button, the original default push button resumes being the default push button and obtains a thick border. Controls Controls are GUI components that provide a well defined behavior, ready to add to your application windows. Some controls are provided by the operating system and are “wrapped” for use in Visual Smalltalk. Others are written in Visual Smalltalk. In this section we briefly describe the operating system provided controls supported in Visual Smalltalk, and give a simple illustration of how to add them to your application windows. Each has a larger interface than we describe here. Explore the interface either in a hierarchy browser or in the Visual Smalltalk Enterprise Encyclopedia of Classes. Visual Smalltalk provides a common interface to many controls that are provided by both Windows and OS/2 operating system platforms. This makes the Smalltalk code portable while allowing the application to use native controls. Other controls are specific to either Windows or OS/2 platforms, and are described separately. Support for many of the controls described below is optional, and must be installed. Locate the desired control in the Services Browser and install it.

130 Visual Smalltalk Enterprise Language Reference Controls

Common Controls Visual Smalltalk includes a large number of controls that are common to all supported operating system platforms. The common interface to these objects ensures that the objects have the native look and feel on any platform. StatusPane A status pane is an area, usually displayed at the bottom of a window, containing one or more display boxes. A status pane is typically used to report the status of the current procedure or to display a short help message. Visual Smalltalk implements status panes in the StatusPane and StatusBox classes. An instance of StatusPane sets up an area within which are displayed any instances of StatusBox. Status or other messages are displayed within the status boxes. By default, the status pane is placed at the bottom of the parent pane, and is the height of the title bar. Also by default, boxes are left justified and resizable. The following code opens a window with a status bar and two status boxes: | statusBox1 statusBox2 statusBoxCollection | statusBox1 := StatusBox new width: 150. statusBox2 := StatusBox new width: 100. statusBoxCollection := Array with: statusBox1 with: statusBox2.

TopPane new addSubpane: ( StatusPane new contents: statusBoxCollection ); open To display messages, set the value of the status boxes: statusBox1 contents: 'a message' StatusPane includes protocol to display brief help messages for menus and menu items. An application assigns help for menu items in a dictionary in which the keys are the menu item selectors and titles, and the values are the help text. The menu owner (a window) responds to the statusPaneHelp: message, which takes either a menu title or a menu item selector as its argument. The application must reimplement statusPaneHelp: method as in the following:

Visual Smalltalk Enterprise Language Reference 131 CHAPTER 4 Building a Graphical User Interface

statusPaneHelp: aKey "Private - Answer the hint text to the StatusPane" ^HelpDictionary at: aKey ifAbsent: [^super statusPaneHelp: aKey]. ToolPane Class ToolPane provides the necessary methods for creating and using a tool pane. You create a tool pane in your application’s open method just as you do for any other subpane. A tool pane window uses a subclass called Tool. To make a tool pane look and behave the way you want, you send the contents: message to it. The parameter of the contents: method is a collection of Tool objects. The tool pane has a default framing size, the height of the title bar. The responsibilities of the Tool class are: • Displaying the bitmap associated with the Tool object. The application must provide a bitmap for each tool, including the up state and the down state for the tool. The default size of a tool is 25 X 22 pixels.. • Performing a selector associated with the tool. The application must also provide a selector and an owner for each tool. The message is sent whenever a tool is clicked. Button A pushbutton with a text string label. Buttons generate the clicked event. In addition to the standard button, the following subclasses provide varicommon variataion: • DrawnButton A pushbutton labeled with a bitmap graphic. • Toggle An abstract class for CheckBox, ThreeStateButton, and RadioButton. A Toggle remembers whether or not the user has selected it. • RadioButton A round button with a text label, supporting two states: selected and unselected. When selected, a radio button has a solid dot inside of the circle. Only one radio button in a group can be selected at a time.

132 Visual Smalltalk Enterprise Language Reference Controls

• CheckBox A labeled box for selecting one of two states: selected or unselected. When selected, the box is filled; otherwise it is empty. More than one check box can be selected at the same time in the same group. • ThreeStateButton A subclass of CheckBox that distinguishes three states: selected, unselected, and indeterminate. EntryField A single-line text edit field. Text can be cut, copied, and pasted to and from the clipboard. • TextEdit A multi-line text editor. Supports tabstops, word-wrap, and search and replace. • TextPaneControl A subclass of TextEdit that provides methods for evaluating Smalltalk expressions, and for matching and adding parentheses, square brackets, quotes, etc. • RichEdit (Windows only) A subclass of TextPaneControl that provides additional formatting protocol and support for Rich Text Format (RTF) files. • FormattedEntryField Restricts input to a selected format, such as positive integer or phone number. ListBox Displays a list of options from which the user makes a selection with either a single or double click of the mouse. ListBox and ListPane have the same protocol, but ListPane is a Visual Smalltalk implementation. • DropDownList Combines an entry field, a pushbutton, and a list which is hidden until the pushbutton is selected. • ComboBox Present a text field that is always visible and a list that may or may not be displayed. • MultipleSelectListBox A list box that allows multiple selections. Selected items are returned as a Collection of items or indices.

Visual Smalltalk Enterprise Language Reference 133 CHAPTER 4 Building a Graphical User Interface

Scroll Bar The scroll bar control provides a standard scroll bar GUI control and events for catching user actions. The scroll bar can be either vertical or horizontal, indicating whether the arrow buttons point up and down or left and right. The minimum: and maximum: messages set the range of values for the scroll bar, left to right or top to bottom. The position: message sets the starting position for the slide button. You also want to set the line and page increment values, which set the slider travel distance when the user clicks on an arrow button or on the bar left or right of the slider. The following code opens a window with a horizontal scroll bar at the top of the main pane: TopPane new addSubpane: ( ( sb := ScrollBar new ) horizontal; "alternatively, #vertical" minimum: 0; position: 0; maximum: 100; lineIncrement: 5; pageIncrement: 25; layoutFrame:( ( LayoutFrame bottomRightRatio: 1@0 ) bottomInset: -30) ); open There is no default frame size for the scroll bar. The left, right, and slide buttons are automatically scaled to fit the frame size. The scroll bar triggers several events in response to the user’s action. Some of the most important events are the following:

Event Triggered when:

changing: Slide bar is in motion c h ang ed: Slide bar has completed its motion nextLine User clicked on right arrow button or pressed right arrow key nextPag e User clicked on bar to the left of the slider or pressed Page Down key previou sLine User clicked on left arrow button or pressed left arrow key previou sPag e User clicked on bar to the right of the slider or pressed Page Up key

134 Visual Smalltalk Enterprise Language Reference Controls

Install the Scroll Bar Tester sample program in the Services Browser for a more complete example of using the scroll bar control. StaticPane An abstract class for controls that signal no events to their owners. They are used to provide information to the user about the current state of the application, and are not used for input. Specific classes are: • GroupBox A rectangle with text in the upper left corner used to visually indicate and label groups of related controls, usually radio buttons or check boxes. •StaticBox Draws a filled rectangle. • StaticGraphic Draws an icon or bitmap. • StaticText A simple text display. • FormattedStaticText Displays text formatted as, for example, a phone number. Several formats are defined. Subtopics Windows 95 Controls Windows versions of Visual Smalltalk include several new controls to support Windows 95. Image Controls The following controls, Header, List View, Tree View, and Button List Box, are closely related, and so will be discussed together. Several controls use “adaptors,” which specify special handling for various control elements. Adaptors are implemented as event handlers. Header Control A Header control displays heading buttons, typically used along the top of a columnular list.

Visual Smalltalk Enterprise Language Reference 135 CHAPTER 4 Building a Graphical User Interface

The header area is added as a subpane, as an instance of Header, with a specified frame size. Items are added to the header by sending the headings: message with a collection of HeaderItem instances. The code below displays this window with a simple header: Figure 4-4: Header Control

headings := OrderedCollection new. headings add: ( HeaderItem new string: 'Name'; alignment: #left; width: 120 ). headings add: ( HeaderItem new string: 'Size'; alignment: #right; width: 60 ). headings add: ( HeaderItem new string: 'Type'; alignment: #left; width: 120 ). headings add: ( HeaderItem new string: 'Modified'; alignment: #left; width: 125 ).

TopPane new addSubpane: (pane := Header new layoutFrame: ( ( LayoutFrame bottomRightRatio: 1@0 ) bottomInset: -30) ; headings: headings); open Each header item has a string, which is dispalyed in the header button, an alignment and a width. The collection of items is gathered into a collection, which the header uses to create the header item buttons. Clicking on a header item triggers two events, clickedIndex: and clicked:. clickedIndex: passes the index of the header item, and clicked: passes the value of the header item. Using these events,

136 Visual Smalltalk Enterprise Language Reference Controls the application can perform some action on the list based on the item clicked, such as changing the sort order based on that column. The header items can also be resized by dragging a button edge. Resizing a button triggers the events resizingIndex:to:, which is triggered each time the mouse is moves during a drag, and resizedIndex:to:, which is triggered when the mouse button has been released at the end of the drag. You need to register handlers for these events, for example, to resize a columnular list that you are using with the header control. The Header Tester sample program, installable in the Services Browser, illustrates more techniques for using the header control, and shows how to use it with a columnular list box. List View Control A list view is a subpane that provides several different views on a list of items. The views available are the standard ones in Windows 95: report view (or “details”), list view, icon view, and small icon view. Of particular interest is the use of both small and regular icon views, which include a bitmap representation of list items in the list. This screen shows the report view, as produced by List View Tester program: Figure 4-5: List View Control

Visual Smalltalk Enterprise Language Reference 137 CHAPTER 4 Building a Graphical User Interface

The list view control builds the header for the report view from a collection of header items, which is passed to the list view pane by the headers: message. In List View Tester this is done in the paneContents: method, which is sent in response to the needsContents event. Bitmaps for the images are read from bitmap files. Also introduced in this example is the use of an adaptor method, paneAdaptors, to register a collection of event handlers. Adaptors provide a flexible way of displaying items when the items displayed may be of a variety of types. Based on the view type (reportView, iconView, etc.), the processing action for the item being displayed. List View Tester registers handlers for providing a file name, large and small icons, and columns. Adding the List View control to the window is a simple matter of adding a ListView subpane, specifying its size, and the view. The List View control triggers a number of events connected with actions on list items. Examine the List View Tester sample program, installable in the Services Browser, for a full example of using this control. Tree View Control A Tree View control displays a hierarchically related collection of items as an expandable tree-like structure. This is familiar from the file list displays common in many GUI applications. The Tree View Tester program uses the tree view to display the class hierarchy:

138 Visual Smalltalk Enterprise Language Reference Controls

Figure 4-6: Tree View Control

The bitmaps are the small closed and open folder images, which are used by the adapter to properly display the items. The paneAdaptor method registers event handlers to manage the different types of object that may be placed in the Tree View pane. The Tree View pane itself is added as usual for subpanes, but with its adaptor method and many other event handlers specified. Examing the Tree View Tester example program, installable in the Services Browser, for a full example of how to interact with the Tree View contents. Button List Box Control The Button List Box control provides a subpane that displays a list of items with check boxes and an image. The check boxes can be two or three state check boxes.

Visual Smalltalk Enterprise Language Reference 139 CHAPTER 4 Building a Graphical User Interface

The screen shown below is produced by the Button List Box Tester sample program: Figure 4-7: Button List Box Control

The Button List Box subpane specifies the framing size, the number of states, the adaptor, and registers additional events. Among the events triggered by the Button List Box are those triggered when a check box changes its state between checked, unchecked, and, in the case of a three state check box, indeterminate. Examine the Button List Box Tester example program, installable in the Services Browser, for an illustration of how to use these and other events. Tab Control The Tab Control provides a collection of pages, which are displayed as if stacked with one on top. Pages are selected by clicking on the page tab. This is similar to the OS/2 Notebook control. Each tabbed page is added to the TabControl pane as an instance of TabControlItem. The item can specify a label and a bitmap or icon image that is displayed on the tab. A short text “tip” can also be set, which is displayed in a tip box when the cursor is positioned over that tab.

140 Visual Smalltalk Enterprise Language Reference Controls

The following code shows how to create a tab control pane and add tab items. The icons are taken from the Visual Smalltalk system icons. images := Icon allInstances copyFrom: 1 to: 3. images := images collect: [ :each | each clone ]. TopPane new addSubpane: ( ( tab := TabControl new ) font: TextFont; addPage: ( TabControlItem new label: 'first'; image: ( images at: 1 ); tipText: 'first tip' ); addPage: ( TabControlItem new label: 'second'; image: ( images at: 2 ); tipText: 'second tip' ) ); open. For a further example, examine the Tab Control Tester sample program, installable in the Services Browser. Property Sheet A Property Sheet is a modeless dialog box used to maintain properties for an object in a multi-page form. A Property Sheet contains a TabControl and three push buttons: OK, Cancel, and Apply. An optional fourth button, Help, can be added. The associated TabControl manages the pages, with each page representing a property of the underlying object. To make creation easier, pages can be added by sending the addPage: message directly to the PropertySheet object instead of to the TabControl. When the OK or Apply button is pressed, the apply event is triggered for each page in the PropertySheet. When the OK or Cancel button is pressed, the PropertySheet closes. When the Help button is pressed, the help event is triggered for the currently selected page. The Apply button is initially disabled, and is enabled after any user input occurs within the pages. When the Apply button is pressed, it is disabled again until the next user input. Install and examine the Tab Control and Property Sheet Sample in the Services Browser for an extended example of how to use Property Sheets.

Visual Smalltalk Enterprise Language Reference 141 CHAPTER 4 Building a Graphical User Interface

Wizard A Wizard consists of a sequence of pages that guide the user through the steps of an operation. The Wizard itself is a modeless dialog box containing a TabControl and three push buttons: Back, Next, and Cancel. An optional fourth button, Help, can be added. The TabControl manages the pages, with each page representing a step in the procedure. The pages do not have page tabs, but the window title changes to the page title whenever the current page changes. To make the creation task easier, pages are added by sending the addPage: message directly to the Wizard object instead of to the TabControl. A page is an instance of TabControlItem, just as for tab controls. The Back button is diabled when the first page is the currently selected page. The Next button is disabled when the last page is the currently selected page, but can be turned into a Finish button and not disabled when the last page is the selected page. When the Back button is pressed, the back: event is triggered, and the default handler displays the previous page. When the Next button is pressed, the next: event is triggered, and the default handler displays the next page. When the Finish button is pressed, the next: event is triggered, and the default handler closes the window. When the Cancel button is pressed, the wizard window is closed. When the Help button is pressed, the help: event is triggered for the currently selected page. Range Controls Range controls provide interfaces for the user to operate on linear range of integer values. Range controls typically set maximum and minimum values for the range, as well as an initial value. Up/Down UpDown is a basic control that displays an up/down arrow button pair, similar to those used on scroll bars. The up/down buttons are always used together with another control, such as a text field or an entry field, which is referred to as its “buddy.” The following example creates a window with an entry field and an up/down control.

142 Visual Smalltalk Enterprise Language Reference Controls

TopPane new addSubpane: ( tp := EntryField new framingBlock: [ :box | ( ( box topLeft right: 20) down: 20 ) extent: 45@30 ] ) ; addSubpane: ( ud := UpDown new framingBlock: [ :box | ( ( box topLeft right: 65) down: 20 ) extent: 15@30 ] ; minimum: 0; maximum: 100; position: 50; buddy: tp ) ; open The buddy: message connects the up/down control with the entry field. The maximum, minimum, and initial position are set for the up/down control, and displayed in the entry field. For a more complete example, see how the up/down control is used with the Spin Button. Spin Button A spin button is a combination of an entry field and an up/down control. The up/down buttons cycle through its range of values as the user clicks on the up and down arrow buttons. The display contents for the entry field can be specified using the contents: message. The items in the collection are displayed in place of the index value. TopPane new addSubpane: ( sp := SpinButton new contents: #( 'one' 'two' 'three'); minimum: 1; maximum: 3; framingBlock: [ :box | (box topLeft rightAndDown: 15@15 ) extent: 200@30] ) ; open A spin button can be either a master or a slave. A slave button is displayed without the up/down control arrows. To connect the slave with its master, send the master: message to the slave with the name of the master spin button as argument. See the Spin Button Tester example, installable in the Services Browser, for an illustration of this.

Visual Smalltalk Enterprise Language Reference 143 CHAPTER 4 Building a Graphical User Interface

Progress bar A progress bar provides a way to graphically show the progress of an operation. This is useful in many cases, especially when the operation takes a long time. The progress bar can indicate how much of the operation has completed, and gives the user an idea of how much longer it will take to complete. The progress bar can be displayed in a dialog, as in this example: DialogTopPane new initialSize: 400@150 ; addSubpane: ( ( pb := ProgressBar new ) minimum: 0; maximum: 100 ; framingBlock: [ :box | box leftTop: 10@50 extent: 180@15 ] ) ; open Track Bar The Track Bar control is a horizontal or vertical slider control used to set values along a range. This control is similar to the OS/2 Slider control. As with the other range controls, you can specify the minimum and maximum values, and the starting position. You can control where the tick marks are displayed (top, bottom, left, or right), and at what increments. The line increment setting (default = 1) determines the increment when the user presses an up or down arrow key. The page increment setting (default = 10) determines the increment when the user presses the page up or page down key, or clicks on the scale to the left or right of the pointer. TopPane new addSubpane: ( ( tb := TrackBar new ) horizontal; minimum: 0; position: 50; maximum: 100; ticksBottom; ticks: ( 0 to: 100 by: 10 ); lineIncrement: 5; pageIncrement: 25; framingRatio: ( Rectangle leftTopUnit extentFromLeftTop: 1@(1/3) ) ); open

144 Visual Smalltalk Enterprise Language Reference Controls

The track bar triggers several events in response to user actions that your application needs to handle. Here are a few of the most important:

Event Triggered changing: At each line increment during a change, while the pointer is being moved. c h ang ed: When a move is complete, as when the mouse button is released. nextLine When the user presses the Down Arrow key nextPag e When the user presses Page Down previou sLine When the user presses the Up Arrow key previou sPag e When the user presses Page Up

Examine the Track Bar Tester sample program, installable in the Services Browser, for an example of how to use these events and other features. Status Window A status window is an area, typically at the bottom of a window, used to display statsu messages. The StatusWindow class allows you to add a Windows native status window to your application display. A Status Window can be in simple mode or non-simple mode. In simple mode, there is a single pane with message contents stored separately from non-simple mode. In non-simple mode, you can specify several status fields and control their widths. The following sample code opens a window with a text pane and a status window. Initially the status window displays two fields, defined as shown. statField1 := StatusField new contents: 'test one'; width: 150; type: #popOut. statField2 := StatusField new contents: 'test two'; width: -1; '' Fill to right border '' type: #popOut.

Visual Smalltalk Enterprise Language Reference 145 CHAPTER 4 Building a Graphical User Interface

TopPane new addSubpane: ( tp := TextPane new framingRatio: ( Rectangle leftTopUnit extentFromLeftTop: 1@ 1 ) ) ; addSubpane: ( statWindow := StatusWindow new simpleModeText: 'this is a simple pane'; contents: ( Array with: statField1 with: statField2 ) ) ; open . Fields for non-simple mode are defined as instances of StatusField, and can contain a string or a bitmap. In simple mode, the single status field can contain a string. To switch to simple mode, send: statWindow simpleMode: true The multiple fields are replaced by a single field. To switch back, set simple mode to false. For other settings for both the Status Window and Status Fields, see the Visual Smalltalk Enterprise Encyclopedia of Classes. Tool Tip A tool tip is the small text window that is displayed when the mouse is positioned over a GUI element for a short period of time without being clicked. A tool tip can be added to any control simply by adding the message tipText: 'a string' to the sequence of messages defining the control. For example: addSubpane: (Button new label: 'Close'; tipText: 'click here to quit'; framingBlock: [ :box | box bottomRight - (60@30) extent: (55@25) ] ); The tipText: message is implemented in Window, so it is available to any GUI element. OS/2 CUA Controls The OS/2 version of Visual Smalltalk includes several CUA controls, provided in Smalltalk libraries. Container A container control is simply a pane for containing representations of other objects, such as files, directories, or programs. You add a container pane to a window as a subpane, and add instances of ContainerItem to it.

146 Visual Smalltalk Enterprise Language Reference Controls

ContainerItem has subclasses to represent some common objects. You can add other objects by creating additional subclasses. The following code opens a container pane in the top 3/4 of the top pane. The container items are directories under the Visual Smalltalk root directory, which are all created as folder items. directories := OrderedCollection new. Directory current subdirectories do: [ :each | directories add: ( each at: 2 ) ]. icon := Icon fromFile: '.\sample\cuactrls\containr\folder.ico'. window := TopPane new addSubpane: ( ( container := Container new ) dragSource; dragTarget; framingRatio: ( Rectangle leftTopUnit extentFromLeftTop: ( 1 @ (3/4) ) ) ). directories do: [ :aDir | containerItem := ContainerFolder new originalObject: aDir; icon: icon. container insertItem: containerItem parent: Directory current. containerItem insertChildrenInto: container ]. container arrangeItems. window open Containers are often used as both drag-drop sources and targets, but this must be declared. Container items are added to the container using the insertItem: message. The item must be an instance of an appropriate subclass of ContainerItem, in this case ContainerFolder. The originalObject: message, which is implemented in each ContainerItem subclass, sets up specific handling required by the type of item. The arrangeItems message makes sure the container item icons are distributed within the container pain. A container can also have a number of detail fields defined for it, as instances of ContainerDetailField. Using these, the container can provide a detail, or report, view of the contained objects. A number of events are triggered by actions on container items. Default handlers are provided for most drag-drop events. For other events, refer to the Encyclopedia of Classes, or browse the constructEventsTriggered: methods in the container classes.

Visual Smalltalk Enterprise Language Reference 147 CHAPTER 4 Building a Graphical User Interface

The Container Tester sample program, installable in the Services Browser, illustrates more details of using the container classes. Notebook The Notebook control provides a collection of pages, displayed as if stacked, with tabs for quickly flipping to specific points in the stack. It is similar to the Tab control on Windows 95. You create an instance of Notebook as a subpane, and specify characteristics such as the size of major and minor tabs, and page layouts. Page layouts are defined as subpanes of the notebook. Notebook pages are created as instances of NotebookPage, and are added to the notebook by sending insertPage:after: or other similar messages to the notebook. A notebook page is associated with a page layout by sending setWindow: to the notebook page. The following code creates code creates a notebook with five pages, each with the same page layout having only a single entry field: window := TopPane new addSubpane: (notebook := Notebook new pageButtonExtent: 30 @ 30; majorTabExtent: 25 @ 20; framingRatio: ((Rectangle leftTopUnit rightBottom: Rectangle rightBottomUnit) insetBy: 1/50)). notebook addSubpane: (pageWindow := NotebookPagePane new addSubpane: (nameField := EntryField new value: nil; framingRatio: ((Rectangle leftTopUnit extentFromLeftTop: 1 @ (1/5)) insetBy: 1/30 ) ) ). 1 to: 5 do: [:i | notebook insertPage: ( NotebookPage new notebook: notebook; major; setWindow: pageWindow) after: notebook size]. window open. notebook firstPage. The major message sent to each notebook page specifies that it has a major tab. A minor tab is set by sending minor.

148 Visual Smalltalk Enterprise Language Reference Controls

After opening the window, sending firstPage to the notebook causes the first page to be displayed. See the Notebook Tester, installable in the Services Browser, sample program for a more complete example of a notebook program. Slider The Slider control is a horizontal or vertical slider control used to set values along a range. This control is similar to the Windows 95 Track Bar control. When you create a slider, you must set the number of increment marks, including the 0 increment, and the spacing between increment marks in pixels. Messages are defined to do this for two sliders. Use scale1Increments:scale1Spacing: for the first slider, and scale1Increments:scale1Spacing: for the second, if there is one. Tick mark sizes are set in pixels. The ticksSize: message sets the standard tick mark size, and tick:size: sets the size of specific tick marks. By default, the slider is placed horizontally in the frame. To make it vertical, send the vertical message. Also by default, the slider is positioned at the bottom of the frame and centered left to right. Use the shaftPosition: message to set the position of the slider. The following creates a single slider: TopPane new addSubpane: ( slider := Slider new scale1Increments: 21 scale1Spacing: 5; ticksSize: 10; tick: 0 size: 20; tick: 9 size: 20; tick: 19 size: 20; tick: 3 text: 'three'; framingRatio: ( ((0 @ 0) corner: (1 @ 1)) ); shaftPosition: 126@160 ) ; openWindow. Slider triggers only one event beyond the standard subpane events, changed:, which passes the slider as its argument. When handling this event, use the selection and selectionInPixels methods in Slider to capture the new slider value. See the Slider Tester sample program, installable in the Services Browser, for a more complete example.

Visual Smalltalk Enterprise Language Reference 149 CHAPTER 4 Building a Graphical User Interface

Spin Button A spin button is an entry field that scrolls through a range of numeric values or a collection of text values. TopPane new addSubpane: ( sp := SpinButton numeric rightJustified; minimum: 1; maximum: 3; framingBlock: [ :box | (box topLeft rightAndDown: 15@150 ) extent: 200@30] ) ; open In this code, the spin button is defined as a numeric field, and so a minimum and maximum must be set to integer values. The spin button can be created to take text values by creating it with either the centeredText, leftJustifiedText, or rightJustifiedText class message. For example: addSubpane: ( sp := SpinButton centeredText contents: #( 'one' 'two' 'three') asOrderedCollection; framingBlock: [ :box | (box topLeft rightAndDown: 15@150 ) extent: 200@30] ) ; You can also define a slave spin button, using numeric:, centeredText:, leftJustifiedText:, or rightJustifiedText:, with the master spin button passed as the argument. The spin button triggers a number of events, indicating that the current value has been changed class method. You can register handlers for these events if other parts of your application need to be dynamically updated. To retrieve the current value of the spin button, send it the getValue message. Value Set A Value Set displays a rectangular grid of objects, and allows the user to select items with the mouse. Locations in the grid are located as points x@y, with x as the row and y as the column. The following code opens a 3-by-4 value set, with 3@1 filled blue and 2@3 displaying “(2@3)”. There are also messages for displaying icons and bitmaps. The following code displays a 3 by 4 value set with the cell at 3@1 colored blue and the cell at 2@3 showing its position.

150 Visual Smalltalk Enterprise Language Reference Dialogs

TopPane new addSubpane: (vs := ValueSet new rows: 3 columns: 4; framingRatio: (0@0 extent: (1/2 @ (1/2) )) ; colorItem: Color blue row: 3 column: 1; textItem: '(2@3)' row: 2 column: 3 ) ; open Cells can be referenced by either row and column position, expressed as a point, or by index. You can translate between these reference methods using the indexOfCoordinate: and coordinateOfIndex: messages. The changedIndex: or changedCoordinate: events are triggered when the value of a cell is changed. The doubleClickedIndex: and doubleClickedCoordinage: messages are triggered when the user double-clicks on a cell. See the ValueSet Tester sample program, installable in the Services Browser, for a larger example of using the Value Set. Dialogs You can build dialog in Visual Smalltalk just as you do other windows. Refer to subclasses of WindowDialog for examples of provide dialog boxes constructed in Visual Smalltalk. These are used by Visual Smalltalk. In addition to building your own dialog boxes, Visual Smalltalk provides several standard dialog boxes that you can include in your application. • Subclasses of CommonSystemDialog wrap host operating system dialogs. •The MessageBox class provides a simple method for displaying a message and getting a response. The Prompter dialog is written in Visual Smalltalk, and is described here because of its general usefulness. Common System Dialogs Subclasses of CommonSystemDialog wrap host operating system dialogs. There are currently four dialog box types: FileDialog, ColorDialog, FontDialog, and PrintDialog.

Visual Smalltalk Enterprise Language Reference 151 CHAPTER 4 Building a Graphical User Interface

File Dialog The File Selection Dialog displays file and directory information from the disk drives to which it has access. This control allows the user to view files and directories, and can be used for either opening a file or for a SaveAs operation. To open the file selection dialog and retrieve the selected file name, evaluate this expression: FileDialog new openFile file Your application can then use the name returned for the necessary file operation. To open a Save As dialog with aFilename as the initial choice, evaluate: (FileDialog new saveFile: aFileName) file The file message returns the file name entered, which your application uses for writing the file. Color Dialog The ColorDialog allows the user to select colors. To retrieve a color as an RGB value, evaluate: ColorDialog new open chosen Font Dialog The FontDialog allows the user to select the font for the current window or pane. To retrieve a selected font, evaluate: FontDialog new open chosen Print Dialog The PrintDialog class, provided on Windows versions of Visual Smalltalk, supports protocol that allows the user to setup and select a printer. Use the following message to invoke the printer setup dialog: PrintDialog printerSetup Message Box Message boxes ares useful for getting quick confirm/cancel or yes/no information from the user. The MessageBox has five public messages:

152 Visual Smalltalk Enterprise Language Reference Dialogs

confirm: aString Display a message box with aString as the title and “Yes” and “No” for the choices. Answer a Boolean: true if the selection is “Yes”; false otherwise. message: aString Display a message box with aString as the content and “OK” for the choices. notify: titleString withText: messageString Display a message box with titleString as its title, messageString as the content, and “OK” for the choices. threeStateNotify: titleString withText: messageString Display a message box with titleString as its title and messageString as the content. Display buttons labeled “Yes,” “No,” and “Cancel.” Answer true, false, or nil. warning: aString Display a warning message box with aString as the text. Prompter Prompter is a modal dialog built in Visual Smalltalk that provides a simple mechanism for soliciting a response to a question. The dialog presents a prompt and a single entry field for entering the answer. To open a prompter, send the following message to class Prompter: Prompter prompt: question default: answer where both question and answer are strings. After the prompter window is opened, the answer string will be shown in its entry field as a default. The message returns a string object as answered by the application user. For instance, Prompter prompt: 'Give me a string please' default: '2 + 3' returns “2 + 3.” If you cancel the prompter, an answer of nil is returned. Modal and Modeless Dialogs Dialogs can be modal relative to its “parent” window, or modeless. If a modal dialog is opened, the user cannot access its parent until the dialog is closed. A modeless dialog does not restrict access to the parent window.

Visual Smalltalk Enterprise Language Reference 153 CHAPTER 4 Building a Graphical User Interface

The default for DialogTopPane is to open modal to the calling window. You can specify another window as the parent using openModal: and specifying the parent. To open the dialog modeless, use openModeless. The procedure for causing modal or modeless behavior for a dialog window that is a subclass of WindowDialog differs from the procedure for subclasses of DialogBox. To make a WindowDialog subclass instance modal to the current window, send the message self openWindow. To make a dialog window modal to a different window, use openModal:. Building Dialog Boxes in Smalltalk You can create dialogs in Smalltalk by adding panes to a DialogTopPane. To create a dialog window using this method, subclass WindowDialog in the ViewManager hierarchy. You need to implement an open or openOn: method and an initWindowSize method. Dialog window and subpane sizes are specified in terms of dialog units, which are 1/4 of the system font’s width and 1/8 of the system font’s height. Typically, measurements are specified as width in characters, and height in lines, and then converted to dialog box units by multiplying such an extent by WindowDialog unitMultiplier. Graphics operations inside any of the subpanes are expressed in pixels, as usual. To use this method, first implement an initWindowSize method to specify the size of the dialog box in dialog units. initWindowSize "Answer the dialog window size. Specify the size as character units and then multiply by unitMultiplier to convert to dialog units." ^(40 @ 15) * WindowDialog unitMultiplier This creates a dialog box 40 characters wide and 15 characters high. Then implement an open method to add the control subpanes and to call openWindow. Using a Resource Dialog Box in Smalltalk You can use a dialog box built outside of Smalltalk and compiled as a resource DLL file. A header (.H) file may accompany the resource file. Resource DLLs are described in more detail in chapter 19, OS Interface and API Calls.

154 Visual Smalltalk Enterprise Language Reference Dialogs

Create a subclass of DialogBox for your resource DLL. Typically you create a separate subclass for each dialog box. Then add a method similar to the following to call the resource DLL from Smalltalk: | dll dlg | dll := DynamicLinkLibrary open: 'MYDLL'. dlg := DialogBox new fromModule: dll id: 'MyDialog'. dlg close. dll close. The open method (or open: or openOn:) sends fromModule:id:, an itemIds method, and a method for each push button, such as ok and cancel. You can also write methods for other controls (see class NewSubclassDialog for an example). The DialogBox class contains methods useful for all dialog boxes, such as queryButton:, queryItemText:, setButton:value:, setItemText:string:. Your itemIds method should answer a dictionary mapping dialog item numbers to selectors. When a WM_COMMAND message is received, DialogBox handles it by looking up the item number in the itemIds dictionary and performing the selector for that item, if there is one. If you produced a .H file from the dialog box editor, you can use DialogBox parseDotHFile: to create a class method which builds your itemIds dictionary from the .H file. You can also use your itemIds dictionary for mapping item names to item numbers so your code that refers to a dialog item can be symbolic: fixed := self queryButton: (ItemIds at: 'fixed'). To open the dialog modeless, simply open the dialog box and return. To open the dialog box modal to the current window, include self processInput as the last line in dialog box’s open method. processInput does not return until another method in your dialog box class sends self close, as when the user closes the dialog box. See NewSubclassDialog for an example.

Visual Smalltalk Enterprise Language Reference 155 CHAPTER 4 Building a Graphical User Interface MenuWindow A MenuWindow can be either the menu bar for an application window or an individual pull-down or pop-up menu. Class MenuWindow has methods to interface with the host system side of the menu windows, and has methods for manipulating the menu bar for an application window. The following are the major MenuWindow instance methods: addMenu: aMenu Add aMenu to the receiver. addMenu: aMenu owner: anOwnerWindow Add aMenu to the receiver and set aMenu's owner to anOwnerWindow. menuTitled: aString Answer the menu whose title is aString. Case is ignored and aString can include $&, $~, or neither. removeMenu: aMenu Remove aMenu from the receiver. Keyboard Mnemonics Menu items, menus, push buttons, checkboxes, and radio buttons support keyboard mnemonics. That is, they can be activated using the keyboard alone, even when they do not have the input focus. In the case of menu items, the keyboard mnemonics is in addition to accelarator keys. To activate a menu item, or subpane that supports a keyboard mnemonic, press and hold the ALT key while pressing the keyboard mnemonic key for that item. The input focus can be anywhere in the main window containing these items. To designate a keyboard mnemonic, the label specified during the creation of menu item or the subpane must have a “~” (a tilde) character preceding the designated character. For example, to designate the character “F” as the keyboard mnemonic for the File menu, the label passed to create the menu must be: “~File.” On Windows, you can use “&” (ampersand) instead of the tilde, but the result is not portable to OS/2.

156 Visual Smalltalk Enterprise Language Reference Cursor Control

Cursor Control Visual Smalltalk uses different cursor shapes to visually indicate system status. For example, the hourglass cursor shape is used to indicate that a computation is in progress. Cursor shapes are also a good way to convey status information about your applications. The Visual Smalltalk cursor is managed by class CursorManager, which provides an interface between Visual Smalltalk and the mouse cursor. The current cursor is stored in the Cursor global variable. Hide and Display Cursor The expression Cursor hide hides the cursor and Cursor display displays it. These two messages must be balanced, one display message for each hidden message. For example, suppose the cursor is currently being shown; if you hide it twice and then display it once, you must still display it again to show it. If you are not sure at which level the cursor currently is, and it is not displayed, evaluate the expression Cursor reset. This forces a balance of hide and display and shows the cursor. Cursor Shapes To change the cursor shape, simply send the message change to the cursor object you desire. For example: CursorManager execute change changes the cursor shape to an hourglass (the execute cursor). If you only want to change the cursor shape temporarily for a block of code, try: CursorManager execute changeFor: [400000 timesRepeat: [ ] ] On the screen, the shape of the various arrows is often described according to compass directions, where north is the top of the screen, south is the bottom, east is to the right, and west is to the left.

Visual Smalltalk Enterprise Language Reference 157 CHAPTER 4 Building a Graphical User Interface

Visual Smalltalk includes the following cursor shapes:

Messages to Shape CursorManager arrow Arrow pointing northwest c rossHair Cross-hairs execute Hour-glass normal I-beam (default cursor) orig in Double-headed arrow pointing northeast and southwest sizeHorizontal Double-headed arrow pointing west and east sizeLeftTop Double-headed arrow pointing northwest and southeast compatible with PARTS Workbench) sizeR ig h tTop Double-headed arrow pointing northeast and southwest sizeVertic al Double-headed cursor pointing north and south text I-beam

Window Properties A window object can have any number of properties, which may or may not have a set value. For example, the background color of a subpane usually takes the system color, there is a color property for those panes requiring a specific color. For efficiency, rather than define a separate instance variable for each property of a window, class Window defines a single instance variable, property, which is implimented as a dictionary, to store all properties at key values. To accessor methods are used to set and get a property value: propertyAt: aSymbol put: anObject Set the property identified by aSymbol to anObject. propertyAt: aSymbol Answer the property identified by aSymbol. If there is no such property, answer nil. Additional accessor methods may be defined for specific properties, which in turn can use propertyAt: and propertyAt:put:.

158 Visual Smalltalk Enterprise Language Reference Window Properties

The following property names are reserved for use by Visual Smalltalk: bac k C olor c h arac terTyped font foreC olor h orizontalExtent su bc lass zoomed

Other names, though not reserved, may be used. Check for senders of propertyAt:put: to avoid collisions.

Visual Smalltalk Enterprise Language Reference 159

CHAPTER Application 5 Coordinators Overview To coordinate the application logic with the GUI, applications are built within an application framework. The framework typically includes an abstract class that provides some basic capabilities for building the GUI and for coordinating the interaction between the application logic and the GUI. The application is modeled in a subclass of this framework class. Using a well constructed application framework helps separate between the application’s logic, or model, and its presentation, or view. This is the preferred way to design Visual Smalltalk applications since it promotes good object-oriented design and increased reusability. Visual Smalltalk provides two application frameworks, built around the ViewManager and ApplicationCoordinator classes. You can use either of these frameworks for your own applications, or use them as models for designing your own framework. In this chapter we will describe the GUI elements provided by the Window subclasses and how to assemble them into a view. The assembly instructions are given in a subclass of the chosen application framework. We will describe how this is done in both the View Manager and Application Coordinator frameworks. Models and Views Smalltalk applications should be built using the Model/View paradigm. Using this approach, you separate the application data and logic, the domain model, from its external interface, the view. The separation of model and view is clearest when the application is broken up, or factored, so that the model and view are built in separate class hierarchies. The view elements are provided in Visual Smalltalk in the Window class. These elements are assembled according to instructions provided by the application. Only view objects are in this hierarchy; application elements, including instructions for building an interface out of the window elements, are elsewhere.

Visual Smalltalk Enterprise Language Reference 161 CHAPTER 5 Application Coordinators

The domain model elements are always specific to the application, and so cannot be provided by Visual Smalltalk. You, the application developer, design and implement a collection of objects, in one or more classes, that model the objects and relations required by the application. Separating the model and view in this way has several important advantages, including: • It promotes responsibility-driven design. The objects that are responsible for generating and manipulating data are isolated from further responsibility presenting that data. • You can develop the core of the application, define classes and behavior, without being distracted by how it is going to look. This frees you to get the logic right. • Reusability of both the model and the view is improved. It is much easier to reuse core application logic and interface logic if the two are kept separate. • The model is accessible to many different views, which can all be displayed simultaneously. When the model is changed, all the active views are updated. Most of the discussion in this chapter focuses on how the application framework manages the view. The framework specifies the structure of the view and mediates its interaction with the model. How the framework manages the model is more difficult to discuss, because it is highly dependent upon the model itself— there are no standard objects and methods. The event system is by far the most flexible and powerful method for managing the model from the framework. An example of using ViewManager, which does the coordination with messages, is provided by the Calculation Window application. The List Keeper provides an example of coordination using events in ApplicationCoordinator. The List Keeper Calculation Window applications can be installed using the Services Browser. The view of a Visual Smalltalk application is typically presented as a collection of window panes. The Class Hierarchy Browser is a good example. It has a main window, which includes the title bar, menu bar, and sizing controls. Inside the window are a number of smaller panes, displaying lists, text, and buttons. The panes all work together, so that when you select an item in the class list, the methods list is updated, and when you select a method name in the methods list, the text pane displays the method expressions.

162 Visual Smalltalk Enterprise Language Reference Coordinating Views and Models

Rather than building a visual interface as a subclass in the Window hierarchy, you specify how to assemble it out of window panes in methods in the application framework subclass. The methods that you actually use differ depending on the framework, but the overall principles are the same. Coordinating Views and Models An application framework helps you create an application with a clean separation of the model and view. It also simplifies and centralizes the task of building the view and opening the application. Most applications will have a subclass of the application framework class as their starting point. The subclass will include the methods that create a view and start the application.

C oordinator

View M odel

The application framework class has three major responsibilities: • start up and shut down the application • create, open and close the view • coordinate the view and model By Smalltalk convention, an application typically begins with an open or openOn: method. This method handles a number of initialization functions. As part of the initialization, the view is built. At this point, there is already a difference between the View Manager and Application Coordinator approaches to building an application. In a View Manager application, you send new to the class, producing an instance to which the open message is sent. For example: MyApplication new open In Application Coordinator, the open message is sent to the class itself: MyApplication open

Visual Smalltalk Enterprise Language Reference 163 CHAPTER 5 Application Coordinators

The essential difference is that, by convention, in View Manager building the view is done with instance methods, whereas in Application Coordinator it is done with class methods. Building a View Manager Application A View Manager application starts by sending the open method to an instance of the appropriate ViewManager subclass. We could build the view right in the open method, but it is better to design the view in a separate createView method. (Early code, even from Digitalk, does not always do this, so beware when looking at examples.) The view definition specifies what panes are used in the view and the conditions under which the view contents need to be updated. Create the View An application is usually started by sending the openOn: or open message to a new instance of the ViewManager subclass. The open method performs any necessary initialization, such as setting instance variable values. Among the list of initializations, you must include one to build the view: self createView. The view creation method is responsible for the design of the application window only. At the minimum, createView does the following: • Create the view using addView:. The view is usually an instance of TopPane or DialogTopPane. You usually set a label, which is displayed in the title bar. • Add one or more subpanes to the view with addSubpane: and set its basic attributes. • For each subpane, define its frame size and position. • For each subpane, register any event handlers. • Set initial pane contents, especially for static controls.

164 Visual Smalltalk Enterprise Language Reference Coordinating Views and Models

The createView method from the CalculationWindow4 (in file CalcWin4.sll) application in the tutorial is a good example: createView |topPane listPane | self addView: ( ( topPane := self topPaneClass new) owner: self; labelWithoutPrefix: 'Calculation Window 4'). self addButtonGroup: topPane. topPane addSubpane: ( (listPane := ListPane new) setName: #calculationPane; when: #needsContents send: #calculationPaneContents: to: self with: listPane ; when: #needsMenu send: #calculationPaneMenu: to: self with: listPane ; when: #changed: send: #clickedOnNum to: self ; framingBlock: [:box | (box leftTop down: (ButtonFont height + 6)) extentFromLeftTop: (box width @ (box height - (ButtonFont height + 6) // 3) ) ] ). topPane addSubpane: ( (graphPane := GraphPane new) removeVerticalScrollbarStyle; removeHorizontalScrollbarStyle; removeBorderStyle; setName: #graphPane; when: #needsContents send: #drawWith to: self ; when: #display send: #display to: self ; framingBlock: [:box | (box leftTop down: (box height // 3) + ( ButtonFont height + 6) ) extentFromLeftTop: (box width @ ( box height - (ButtonFont height + 6) // 3 * 2))] ). We’ll look at this in three pieces: identifying the panes, configuring events, and setting the frame size. We also describe how to build a menu for a pane.

Visual Smalltalk Enterprise Language Reference 165 CHAPTER 5 Application Coordinators

Identify the Panes First, consider just the parts that define the panes themselves, with minimal properties. We’ll ignore the buttons. self addView: ( ( topPane := self topPaneClass new) owner: self; labelWithoutPrefix: 'Calculation Window 4'; topPane addSubpane: ( (listPane := ListPane new) setName: #calculationPane; ... ). topPane addSubpane: ( (graphPane := GraphPane new) removeVerticalScrollbarStyle; removeHorizontalScrollbarStyle; removeBorderStyle; setName: #graphPane; ... ). ). These lines set up the view and a collection of panes. The view itself is created by sending the addView: message to self, which is the application, an instance of ViewManager. The expression: self topPaneClass new creates an instance of TopPane, the same as TopPane new would. The topPaneClass message returns the default top pane class of the receiver, which is just TopPane in this case. The resulting pane is also assigned the local variable name topPane, which will be used to refer to the pane. ViewManager keeps a list of views for the application in the views instance variable. This variable is initialized to an OrderedCollection. For every addView: you send to the application, a new view is added to the collection. In View Manager, this forms the basis for creating multiple views. The owner is set here since it is used to determine what the standard menus are and how they’re handled. The labelWithoutPrefix: message sets the contents of the window title bar without the “Visual Smalltalk” prefix. The next two sections add subpanes to the view. Both send addSubpane: to topPane, identifying it as their parent. The subpanes are created as instances of ListPane and GraphPane, respectively. This time the class is specified explicitly, since there is no default subpane class.

166 Visual Smalltalk Enterprise Language Reference Coordinating Views and Models

The new panes are each assigned to a variable for later reference. The list pane is assigned to a local variable, since it is only used within the method. The graph pane is assigned an instance variable, since it is referred to by other methods in the application. Each is also assigned a name using setName: followed by a symbol. These names are used by the event managing system. Parent and Child Panes The parent/child relation between panes is important for understanding how subpanes are displayed. The child pane displays as follows: • The size and position of the child pane are always determined relative to and within its parent pane. If the parent moves, the child moves with it. • The child pane is clipped to the boundaries of its parent’s client area. • A child pane is always displayed “on top” of its parent pane. • If the parent pane is hidden or closed, all its children are also hidden or closed. This example has a very simple parent/child structure. The Class Hierarchy Browser has a more complex parent/child structure, having a three level parent/child hierarchy. The instance and class radio buttons have a common parent, a group pane. The group pane in turn is a child of the top pane, as are also the three list boxes and the text pane. Configure Events The event system is a general mechanism for causing actions to occur in response to specific conditions. Events are especially important for updating the contents of window panes. Panes trigger specific events in response to changes in their environment. For instance, most panes trigger a needsContents event when first created. Several panes trigger a changed: event when the user makes a selection in them, such as clicking on an item in a list box. In order for the view to change in any way when a pane triggers an event, it must register an event handler with the pane for that event. This is done with one of these: when: anEvent send: aMessage to: aReceiver when: anEvent send :aMessage to: aReceiver with: anArgument

Visual Smalltalk Enterprise Language Reference 167 CHAPTER 5 Application Coordinators

when: anEvent send: aMessage when: anEvent do: aBlock when: anEvent evaluate: anAction Each tells the pane to send a message whenever it triggers the specified event. We can use when:send: if we have specified an owner for the pane. We use when:send:to: to send a unary message, and when:send:to:with: to specify an argument, for instance if we send a keyword message. The when:do: and when:evaluate: messages allow registering evaluable actions. Our createView method registers handlers for five events. For the list pane, we have: when: #needsContents send: #calculationPaneContents: to: self with: listPane ; when: #needsMenu send: #calculationPaneMenu: to: self with: listPane ; when: #changed: send: #clickedOnNum to: self ; For the graphics pane we have: when: #needsContents send: #drawWith to: self ; when: #display send: #display to: self ; Notice that the event name and message name are given as symbols. Both panes trigger a needsContents event when they are created. The messages following send: are defined by the application in its ViewManager subclass. The list pane sends self calculationPaneContents: listPane self refers to the application. The message requires an argument, so the when:send:to:with: form is used. The graph pane sends self drawWith which gets the graphic tool. Again, self is the application. A list pane also triggers the needsMenu event when it is created, and the application has a handler for it. A list pane triggers the changed: event when the user makes a selection in it, selecting a list item. When this happens, the application wants a change made in the graph pane, so it registers a handler for the event.

168 Visual Smalltalk Enterprise Language Reference Coordinating Views and Models

The Visual Smalltalk Encyclopedia of Classes lists and describes the events triggered by the various window panes. You also can get a list of the events triggered by a pane class by sending the eventsTriggered message to the class, for example: ListPane eventsTriggered Define Menus for Panes If a pane triggers the needsMenu event during its creation, a method can be specified to define a menu. To do this, we first register an event handler for the event, as we did in our earlier example: when: #needsMenu send: #calculationPaneMenu: to: self with: listPane ; When the pane triggers the needsMenu event, it sends calculationPaneMenu: to the application with the pane as its argument. The method adds a pull-down menu to the menu bar, and also pops-up the menu if the right mouse button is clicked while the mouse is over the list pane. calculationPaneMenu: aPane " Private - Set the calculation pane menu " aPane setMenu: ((Menu labels: 'Set ~Number...\~Primes\~Squares\ ~Factorials' withCrs lines: #(1) selectors: #(newNumber primes squares factorials )) title: '~Calculation'; owner: self; yourself) The string argument to labels: contains the items to be shown in the menu. The items are all separated with a backslash (\). The withCrs message replaces the backslashes with carriage returns in its receiver string, so each item is displayed on a different line. Characters preceded by a tilde (~) appear underlined in the menu. If the item is in the menu bar, the user can select the item by pressing Alt and the character key. If the item is in a menu, the user can select it by pressing the character key when the menu is displayed. An ampersand (&) can be used instead of the tilde on Windows platforms, but only the tilde works with both Windows and OS/2 versions of Visual Smalltalk. The argument to selectors: is an array of message selectors to send to the receiver when the corresponding menu item is selected. There must be one method for each label, and placed in

Visual Smalltalk Enterprise Language Reference 169 CHAPTER 5 Application Coordinators

the same order. The methods must be defined in the application’s ViewManager subclass, since the instance of that class is the receiver. The argument to title: assigns a name to the menu in the menu bar of the window. Note that the method that sets the menu for a pane must create a new instance of Menu. Menus will not work properly if a method creates one Menu object, saves it in a class or global variable, and then attempts to use it to set the menus for several different panes. Building an Application Coordinator Application The Application Coordinator framework makes some of the Model/View distinctions a bit clearer, beginning with its open methods. A number of application initialization methods are implemented as class methods rather than as instance methods, reflecting the idea that these methods belong in the instance creation phase of an application. Application Coordinator makes more use of the event mechanism than does View Manager. Within the ApplicationCoordinator hierarchy, there are methods for defining and managing events that an object can trigger. These are often reimplemented by subclass. In this discussion, we use a simple program called ListKeeper (which can be loaded using the Services Browser), to illustrate the methods used by Application Coordinator. Our discussion will be somewhat briefer, highlighting where Application Coordinator differs from View Manager. A lot of what we have said about View Manager, such as about building menus, applies to Application Coordinator as well. Opening the Application As mentioned earlier, the action begins with the open class method. For ListKeeper, this is: open "Create the structure of the main window." | coordinator view | coordinator := self new. view := self createViewFor: coordinator. self buildView: view forModel: coordinator. view open. ^coordinator

170 Visual Smalltalk Enterprise Language Reference Coordinating Views and Models

This method begins by making instances of the application class and the main pane of the view. The coordinator temporary variable is used to refer to the instance of the ApplicationCoordinator subclass itself. Think of it as referring to the application as a whole. The view temporary variable is set to the result of createViewFor:, another class method in this framework. This method can be redefined, but can frequently be used as inherited from ApplicationCoordinator. Its primary task is to create the top window pane: createViewFor: aCoordinator "Create and configure a window for ." | window | window := self windowClass new. window windowPolicy: self windowPolicyClass new. aCoordinator when: #closeApplication send: #close to: window. ^window The window is created as a new instance of the default window class, which is returned by the windowClass class method. A general event handler is registered to close the window when the closeApplication event is triggered. The remaining methods now can refer to the coordinator and its view. The first to do so is buildView:forModel: in the open method. This method is always implemented in the application subclass: buildView: aView forModel: aCoordinator "Create the structure of the main window." aView initialSize: 325 @ 200. aView label: 'Phone List'. self makeListPane: aView on: aCoordinator. self makeTextPane: aView on: aCoordinator. self makeAddButton: aView on: aCoordinator. self makeRemoveButton: aView on: aCoordinator. This method sets the initial window size and the label, and then calls a number of methods each of which adds a pane to the main window. As a sample, look at makeTextPane:on:.

Visual Smalltalk Enterprise Language Reference 171 CHAPTER 5 Application Coordinators

makeTextPane: aView on: aCoordinator "Make the pane in which the user can type new list items." | pane | pane := TextPane new. pane when: #needsContents send: #setTextContents: to: aCoordinator with: pane. aCoordinator textContentsHolder when: #changed: send: #update to: pane. aCoordinator when: #needsText send: #contents to: pane. pane layoutFrame: ((LayoutFrame topLeftRatio: 0 @ (1/2) bottomRightRatio: 1 @ 1) topInset: 10; leftInset: 10; bottomInset: 10; rightInset: 10). aView addPane: pane The pane is defined as a new TextPane. Three event handlers are registered, but only one is for an event triggered by the pane. The other two events are triggered by the coordinator and the coordinator’s textContents instance variable. This method also sets the pane size, relative to the top pane, then adds the pane to the view. Finally, the open method opens the view and returns the coordinator instance. Adding Events to Trigger The Application Coordinator framework includes a simple method for defining events that its instances can trigger. Again, events are specified in class methods. The class method constructEventsTriggered adds events to the set of events already triggered by the superclass. constructEventsTriggered "Add the event #needsText to the list of supported events defined by the superclass, so that we can check for errors when configuring events."

^super constructEventsTriggered copy add: #needsText; yourself

172 Visual Smalltalk Enterprise Language Reference Coordinating Views and Models

The method creates a copy of the list of events triggered for the superclass, which is a set, then adds an event, needsText, to the list. The event can now be triggered by the coordinator by issuing the triggerEvent: message. The list of events triggered must be set before beginning the application. The class hierarchy initializes the superclass events and adds any special events included in the subclass constructEventsTriggered method. Using Shared Values In this application, both the list pane and the text pane may need to know when the other has changed. We can use shared values to make updating these panes somewhat simpler. An instance of the class SharedValue is an object that any other object can refer to. By configuring an action for the SharedValue instance’s changed: event, the other object is informed when the shared value changes. The instance of SharedValue holds a value which is another object, for example, the Boolean object true. One of the objects that shares the SharedValue might send the SharedValue instance the message setValue: false, causing the SharedValue instance to change from true to false. After doing so, the SharedValue instance sends itself the message changed, generating the event changed:. Any object that has configured an action to this event is then sent the appropriate message, causing the object to update itself in whatever manner has been specified. If you wish to change the value of a shared value without generating the changed event, you can use the message value: instead of setValue:. We will take advantage of shared values for the List Keeper; each of its instance variables will be a shared value. The initialize instance method is as follows: initialize "Initialize the list editor using three shared values to hold the list, the selected item, and the contents of the text pane. Using shared values for these variables allows us to take advantage of the event that shared values can trigger and respond to."

listContents := SharedValue on: SortedCollection new. listSelection := SharedValue on: nil. textContents := SharedValue on: String new

Visual Smalltalk Enterprise Language Reference 173 CHAPTER 5 Application Coordinators

Because the instance variables hold a shared value, the setting and accessing methods are a bit different. Here is a representative set. Methods to set and access the textContents variable follows the same pattern. For example: listContents "Return the contents of the list, as held by the shared value." ^listContents value listContents: aSortedCollection "Set the contents of the list in the shared value." listContents setValue: aSortedCollection listSelection "Return the selected list item, as held by the shared value." ^listSelection value listSelection: aString "Set the selected list item in the shared value." listSelection setValue: aString And we need one more method to access the shared value itself: listContentsHolder "Return the shared value that holds the contents of the list." ^listContents

174 Visual Smalltalk Enterprise Language Reference CHAPTER 6 Drag/Drop Overview "Drag/drop, also known as direct manipulation, is a user interface technique commonly used in GUI systems. Drag/drop allows operations such as printing, cutting, copying, and pasting to be accomplished in a direct and intuitive approach using the mouse. For example, to print a document the user simply selects the document in a file list and drags it to the printer icon. Visual Smalltalk implements a single drag/drop model that is common to both the Windows and OS/2 platforms. User Interface A drag/drop operation is initiated by selecting one or more objects in a window pane, an instance of a SubPane subclass, with the selection mouse button (typically left on Windows, right on OS/2) and, while holding down the button, dragging the selected item to another location. When the mouse cursor is in the desired location, it is dropped by releasing the mouse button. On Windows platforms, the right mouse button initiates an extended drag/drop operation. When the user drops the item, a pop-up menu displays, showing drag/drop operations. By default, the options are move and copy, but other operations can be added by the application. The application must determine what items are selected when a drag/drop session begins in a source pane, and what action to perform when objects are dropped onto a target pane.

Visual Smalltalk Enterprise Language Reference 175 CHAPTER 6 Drag/Drop Programming Interface The programming interface is based on four objects: drag/drop source The window pane that is the source of the drag/drop transfer. This is where an item is selected for dragging to a target location. drag/drop target A window pane that can receive a drag/drop transfer. The current candidate target is the window below the mouse cursor at the current point in the drag operation. drag/drop object. An object that is created by a drag/drop source when an item is selected in a drag/drop source. This object can be queried about its contents during a transfer as it passes over a potential target or when it is dropped on a target. drag/drop session A model of the drag/drop transfer. It contains information about the source, the current candidate target, the object or objects being dragged, and other related data. Drag/drop objects and sessions are implemented in two class hierarchies: DragDropObject and DragDropSession. Methods for declaring a pane a drag/drop source or target are implemented in class Window.

Figure 6-1: Drag/Drop Objects

Drag Session

Some text

Some text

Drag Objec t

Drag Sou rc e

Drag Targ et

176 Visual Smalltalk Enterprise Language Reference DragDropObject

DragDropObject When the user initiates a drag/drop transfer, by clicking and holding down the mouse button while moving the mouse, the currently selected items are specified in a collection of one or more drag/drop objects. This collection represents the objects in the drag/drop session that models the transfer. Each instance of DragDropObject or one of its subclasses represents a single item being dragged. Each instance may have one or more data formats. For example, a dragged text selection from a word processing application could be represented by a DragDropObject instance containing data formats for both plain text (string) and rich text (rtf). Formats typically are specified by the drag source. Subclasses of the class DragDropObject are defined to parallel the DragDropSession hierarchy. This reflects the fact that different classes of DragDropSession may have different ways of rendering data formats. For example, on OS/2, a LocalDragDropSession needs to do very little to answer data in a particular format, just answering a contained object, whereas a GlobalDragDropObject or OS2DragDropObject must interface with the underlying host to render data in the specified format, and answer a corresponding Smalltalk object. DragDropObject Messages The following are the primary public messages for this class: Class Methods bitmap: aBitmap Answer a new instance of the receiver class containing the single format defined by aBitmap. metafile: aMetafile Answer a new instance of the receiver class containing the single format defined by aMetafile. object: anObject Answer a new instance of the receiver class containing the single format defined by anObject. string: aString Answer a new instance of the receiver class containing the single format defined by aString.

Visual Smalltalk Enterprise Language Reference 177 CHAPTER 6 Drag/Drop

Instance Methods availableFormats Answer an ordered collection of strings identifying the formats available in the receiver; redefined by subclasses. bitmap Answer a bitmap representation of the receiver, or signal an error if no such format is available. bitmap: aBitmap Add aBitmap to the receiver’s data formats. format: formatTypeString Answer data in the specified format, or signal an error if no such format is available; redefined by subclasses. format: formatTypeString data: formatData Set the data for the given format to formatData; redefined by subclasses. hasBitmap Answer whether a bitmap representation is available. hasFormat: typeNameString Answer whether the receiver can provide data in the given format. Redefined by subclasses. hasMetafile Answer whether a metafile representation is available. hasObject Answer whether an object representation is available. hasString Answer whether a string representation is available. metafile Answer a metafile representation of the receiver, or signal an error if no such format is available. metafile: aMetafile Add aMetafile to the receiver’s data formats. object Answer an object representation of the receiver, or signal an error if no such format is available. object: anObject Add anObject to the receiver's data formats. string Answer a string representation of the receiver, or signal an error if no such format is available.

178 Visual Smalltalk Enterprise Language Reference DragDropSession

string: aString Add aString to the receiver's data formats. DragDropSession DragDropSession is a class whose instances model the drag/drop transfer and manage the interaction between drag source and drag target. The session performs the transfer negotiation between a drag source and candidate drag targets. This involves: • determining whether the object is acceptable to the candidate target, • determining what operation should occur given the object being dragged, the state of the target, and other influences such as shift key state, • providing user feedback, such as displayed cursors, indication of target selection, and target scrolling. This negotiation is managed primarily through the use of the event system. All events are optional in this system, so that if an event is left unhandled, appropriate default behavior is provided. Events and default event handlers are exposed through the Window hierarchy, so that default event handlers can provide behavior appropriate to the type of control window, although event handlers may be implemented in any kind of object. The protocol is defined to be supportable either with or without the aid of underlying operating system support for drag/drop. LocalDragDropSession models an intraprocess drag/drop transfer using only basic Smalltalk facilities, and does not assume an underlying host drag/drop interface. In addition, on OS/2 GlobalDragDropSession models a cross-process drag/drop transfer using common OS drag/drop services. The OS2DragDropSession subclass takes advantage of specific host drag/drop capabilities. DragDropSession Messages The following are the primary public messages for this class: Class Methods objectClass Answers the class to use for DragDropObjects which are added to objects of the receiver class. Implemented by subclass.

Visual Smalltalk Enterprise Language Reference 179 CHAPTER 6 Drag/Drop

source: anObject Create a new instance with anObject as the drag source. Instance Methods impliedOperation Answer the drag/drop operation implied by the current state of the shift keys (Alt, Control, Shift). If no shift keys are toggled, answer nil, meaning that the target application’s default operation is implied. objectClass Answer the class to use for DragDropObjects added to the receiver. objects Answer the objects being dragged. objects: aCollection Set the objects being dragged to aCollection. operation Answer a symbol specifying what would happen if the drag object were dropped right now at the current location and over the current target (move, copy, link, nil, or some other user-defined operation). operation: operationName Set the operationName that specifies what would happen if the drag object were dropped right now at the current location and over the current target (move, copy, link, nil, or some other user-defined operation). operations: aCollection Set the collection of operations that the current target can accept to aCollection. screenLocation Answer a point which is the current location of the cursor relative to the screen. scroll: aBoolean Set a flag which determines whether visual feedback is required to indicate scrolling (cursor). source Answer the drag/drop source. source: anObject Set the drag/drop source to anObject. target Answer the drag/drop target.

180 Visual Smalltalk Enterprise Language Reference Source and Target Panes

target: anObject Set the drag/drop target to anObject. targetLocation Answer a point which is the current location of the cursor relative to the current target. targetSelection Answer the selection within the target if any. targetSelection: anObject Set the selection within the target to anObject. Source and Target Panes Drag/drop sources and targets are instances of ListBox, MultipleSelectListBox, ListPane, TextPane, and TextPaneControl. Enabling and Disabling Drag/Drop To make a pane a drag/drop source or target, include one of the following messages in the pane definition (see the examples later in this chapter): dragSource Enable the pane as a source dragSource: aBoolean Enable (true) or disable (false) the pane as a source dragTarget Enable the pane as a target dragTarget: I Enable (true) or disable (false) the pane as a target. dragTargetForFormats: formats operations: operations Enable the pane as a target for specified object formats and operations. Configuring Events Drag/drop source and target panes trigger several events during the various stages of a drag/drop session. The events triggered are:

Visual Smalltalk Enterprise Language Reference 181 CHAPTER 6 Drag/Drop

Drag source dragSourceNeedsObject: aDragDropSession The session needs to know what items are being dragged, and the event handler specifies this via the objects: message. Default event handlers defined in specific Window subclasses use their current selection to specify the dragged objects. dragSourceCut: aDragDropSession The session has finished a move operation, and the original source selection should be removed. Default event handlers defined in specific Window subclasses use their current selection to determine what to remove. Special handling is required when the source is the same as the target. Drag target dragTargetNeedsOperations: aDragDropSession (Windows only) The session has completed an extended drag/drop transfer, and needs the list of drag/drop operations that the target can process. The handler should set this list using an operations: message. This event is used only for extended drag/drop. If not specified, the default handler specifies the move, and copy operations. dragTargetEnter: aDragDropSession The mouse has entered the bounds of the receiver during a drag/drop transfer. The handler should tell the session what would happen if the drag were to be concluded (object dropped) at the current location over the receiver, by sending operation: to the session with an operation name as an argument (e.g., #move, #copy, some application- defined operation name, or nil if the target should not accept the transfer). The default handler uses the information specified when the target was initialized with dragTargetForFormats:operations: to determine what to pass as an argument to operation:. dragTargetLeave: aDragDropSession The mouse is leaving the bounds of the receiver during a drag/drop transfer. No particular processing is required at this point. The default handler uses this as an opportunity to turn off target scrolling if it was taking place. dragTargetOver: aDragDropSession The mouse is being moved over the bounds of the receiver during a drag/drop transfer. The handler should tell the session what would happen if the drag were to be

182 Visual Smalltalk Enterprise Language Reference Source and Target Panes

concluded at the current location over the receiver by sending operation: to the session with an operation name as an argument (e.g., #move, #copy, #link, some application-defined operation name, or nil if the target should not accept the transfer). It should also process drag target scrolling if necessary. The default handler indicates the operation as in the dragTargetEnter: default handler, and initiates and processes drag target scrolling if necessary. dragTargetDrawEmphasis: aDragDropSession The target or target handler should draw target emphasis for the given session to indicate the location of the cursor. dragTargetEraseEmphasis: aDragDropSession The target or target handler should erase the target emphasis previously drawn by dragTargetDrawEmphasis:. dragTargetDrop: aDragDropSession The mouse button was released over the receiver at the end of a drag/drop transfer. The handler should query the contents of the drag/drop transfer (the objects list in the session argument), and perform whatever application- specific logic is necessary to process the given drag/drop operation (move, copy, link, or some application-defined operation name). The default handler is Window subpane specific, and performs drop handling appropriate to the Window subclass (such as inserting an item into a ListBox). Default handlers are provided for most of these events, but you can define your own handlers for special processing. Register your event handler as usual in the pane definition. Drag/Drop Messages Window dragSessionClass: aClass Set the class to use to model a drag/drop transfer to aClass. dragSource Enable the receiver as a drag/drop source. dragSource: aBoolean Enable or disable the receiver as a drag/drop source. dragTarget Enable the receiver as a drag/drop target.

Visual Smalltalk Enterprise Language Reference 183 CHAPTER 6 Drag/Drop

dragTarget: aBoolean Enable or disable the receiver as a drag/drop target. dragTargetForFormats: formats operations: operations Enable the receiver as a drag/drop target which accepts the specified DragDropObject formats and drop operations. If this method is used to setup a drag target instead of dragTarget, the dragEnter: event can be left unhandled and a default handler will be provided. SubPane dragTargetEmphasisDefault Set the type of target emphasis to be employed to be the default. dragTargetEmphasisItem Set the type of target emphasis to be employed to be item based. dragTargetEmphasisPane Set the type of target emphasis to be employed to be pane based. dragTargetEmphasisSeparator Set the type of target emphasis to be employed to be separator based. Examples A few examples of how to use drag/drop are provided in ViewManager subclasses: DragDropSample, DragDropEventTester, and DragDropPaneTester, plus DragDropInspector on OS/2. These examples are contained in Smalltalk libraries in the EXAMPLES\DRAGDROP directory. After installing a library, run the demo program by evaluating the startup expression using DoIt, for example: DragDropSample open Then, drag items from the top list box to the panes below it.

184 Visual Smalltalk Enterprise Language Reference CHAPTER Handling 7 Exceptions Overview Visual Smalltalk provides protection mechanisms for catching errors and ensuring that the system remains in a consistent state as far as possible: • Ensured Execution Two mechanisms are available to guarantee execution and ensure that the system is not left in an inconsistent state. • Exception Handling The Exception class and its subclasses is used for signaling and handling exception conditions. For a discussion of the control structures, based on blocks, in which these protection mechanisms are employed, see Control Structures in chapter 1. For a discussion of protection mechanisms at the virtual machine level, refer to Protection Violation Handling in chapter 19. Ensured Execution If the system experiences an unusual flow of logic, or if an exceptional condition interrupts processing, the system could be left in an inconsistent state. Visual Smalltalk provides two mechanisms which you can use to ensure that the system remains consistent: •The ensure: message is used to ensure that a block is evaluated, even if evaluation of another block fails. The argument block is unconditionally evaluated. •The ifCurtailed: message is used to evaluate a block if evaluation of another block fails. The argument block is conditionally evaluated.

Visual Smalltalk Enterprise Language Reference 185 CHAPTER 7 Handling Exceptions

Two common uses for these mechanisms are: • To restore invariants in the state of an object when those invariants cannot be preserved during a computation. If the computation does not complete, the value of the invariants might be left in the wrong state, causing problems. • To perform cleanup functions critical to the operation of a system. Ensuring Execution Always Suppose a method sends a sequence of messages causing a great many other methods to execute. Early in the sequence, a file is opened, and the last line in the method closes the file. And suppose in the middle of the method, an error block returns a value which returns prematurely from all the intervening methods, including the original one. Perhaps the error encountered really does make further processing pointless, but the file should be closed in any case. Unfortunately, it won’t be, because the last line in the original method is not executed. The following method illustrates this example: someMethodIfError: errorBlock |myFile| myFile := File open: 'fileName'. self processFile: myFile ifError: errorBlock. myFile close "If errorBlock returns explicitly, the line above will not execute." anotherMethod self someMethodIfError: [^nil] The solution is to identify portions of code in your application that require protection and use the ensure: message to protect them. The ensure: message is sent to a block and takes another block as an argument. The receiver of the message is the block of code that requires protection, the protected block. The argument to the message is the block of code that performs the necessary cleanup, the cleanup block. The syntax is: [protectedBlock] ensure: [cleanup block] Using this mechanism ensures that, if the protected block is executed, the cleanup block will be executed as well. When sent to a block, the message ensure: causes the receiver—the protected block—to be evaluated just as if it had received the

186 Visual Smalltalk Enterprise Language Reference Ensured Execution message value. The value returned is the result of evaluating the receiver—the protected block. After evaluating the receiver, the cleanup block is also evaluated. The following method shows the example above as it would be rewritten to ensure that a file, once opened, is always closed: someMethodIfError: errorBlock |myFile| [myFile := File open: 'fileName'. self processFile: myFile ifError: errorBlock] ensure: [myFile ~~ nil ifTrue: [myFile close]]. The method above also closes the file properly if the process was interrupted for some reason other than an error being encountered. The cleanup block is automatically evaluated if the receiver block does not return normally for any reason. In particular, if an exception terminates the evaluation of the receiver, the cleanup block will be executed. Executing an explicit return from another method outside the receiver block also causes the cleanup block to execute. Another example is a method that places a lock on an external file. As long as the lock is in place, other users cannot access the file. Such a lock must be released even if an exception occurs. The following is an example of a method that could be written in class FileStream to implement such behavior: whileLockedDo: aBlock "Lock the receiving file. Process the argument block while the file is locked then unlock the file. Return the value of the argument block. Be sure to release the lock if an exception occurs." self lock. "set the lock" ^aBlock ensure: [self unlock "clear the lock"] Another method could then count on this mechanism: myFile whileLockedDo: [myFile atEnd ifTrue: [^nil] ifFalse: [myFile next]] The cleanup block within whileLockedDo: is executed even if the argument block encounters an end-of-file and explicitly returns nil.

Visual Smalltalk Enterprise Language Reference 187 CHAPTER 7 Handling Exceptions

Ensuring Execution Under Exceptional Circumstances Opened files always need to be closed, but not all cleanup operations are always necessary. Some are necessary only if the operation being performed doesn’t complete execution for some reason. Occasionally it is necessary to guarantee that a block of code will execute only if another block does not complete normally. For example, from the user’s point of view, opening a window is a single operation. But, the process of opening a window is in fact a complex series of operations. At any given point in the process, the system is in one of a series of intermediate states, each of which is not expected to last any longer than it takes to go on to the next state. In these intermediate states, the system is not expected to process input from the user. If the process of opening a window were to execute halfway and then stop, the system would be in an inconsistent state, and user input (or other actions) could cause problems. The solution is to identify portions of code in your application that perform sequences of operations that must complete, and use the ifCurtailed: message to perform vital cleanup if they do not. The ifCurtailed: message works like the ensure: message described above. It is sent to a block and takes another block as an argument. The receiver of the message is the protected block. The argument to the message is the cleanup block. The syntax is: [protectedBlock] ifCurtailed: [cleanup block] When sent to a block, ifCurtailed: causes the receiver to be evaluated just as if it had received the message value. The value returned is the result of evaluating the receiver, the protected block. The ifCurtailed: message differs from ensure: in only one way. The cleanup block is evaluated only if, for any reason, the receiver block does not return normally. If an exception handler terminates the evaluation of the receiver, the cleanup block will be executed. Executing an explicit return from another method outside the receiver block also causes the cleanup block to execute. For example, the following method moves an element from one collection to another. If the second collection cannot be added to for some reason, it is important to make sure that the element remains in the first collection. However, the method below does not protect against this circumstance:

188 Visual Smalltalk Enterprise Language Reference Exception Handling

moveFirstTo: anotherCollection "Move the first element from the receiver to the last element of the argument."

| element | element := self removeFirst. anotherCollection addLast: element This operation could be protected using the ifCurtailed: mechanism: moveFirstTo: anotherCollection "Move the first element from the receiver to the last element of the argument. If the element cannot be added to the argument leave the receiver unchanged."

| element | element := self removeFirst. [anotherCollection addLast: element] ifCurtailed: [self addFirst: element]. Nesting Protection Blocks Both ensure: and ifCurtailed: protection blocks can be nested as deeply as an application requires. Protection blocks execute in last-in, first-out order. That is, the last protection block to be defined executes first. Then, the second-to-last executes, and so on until finally the first one defined executes. Exception Handling Exceptions are unusual or undesired events that can occur during the execution of a Smalltalk application. While not all exceptions are errors, errors are among the most important exceptions that your application needs to handle. When an exception occurs, an application may need to take some special action. For example, if an application is reading data from a file and unexpectedly encounters an end-of-file, we may want to to stop processing and display an error message. Using the exception handling features in Visual Smallltalk, the application can trap the exception and invoke the special processing.

Visual Smalltalk Enterprise Language Reference 189 CHAPTER 7 Handling Exceptions

The Exception Hierarchy In Visual Smalltalk, exceptions are represented as objects. At the top of the hierarchy is the class Exception. It has several direct subclasses, the two most important being Error and Notification. These and other subclasses are used by the Visual Smalltalk development system for its own error handling, and most should not be referred to by your application. Subclasses of all these defining different kinds of exceptions. Each exception class defines a default action to be performed when that exception occurs. The following table lists some common exception classes with the exceptional event represented by the class and the default action it performs.

Table 7-1: Exception Classes and Their Default Actions

Exception Class Exceptional Event Default Action ArithmeticError Any error evaluating an Inherited from Error arithmetic operator ControlError Any error associated with Inherited from Error evaluating blocks or sending messages Error Any program error Open a walkback FileError Any error associated with Inherited from Error processing files FileSystemError Any error associated with Inherited from Error accessing files MessageNotUnderstood A message was sent to an Inherited from Error object that did not define a corresponding method Notification Any unusual event that does Do nothing, continuing not impair continued executing execution of the program ProcessTermination A Smalltalk process is Inherited from Notification ending Warning An unusual event that the Open a message box that user should be informed describes the event and about allows the user to choose to continue execution ZeroDivide An attempt to divide by zero Inherited from ArithmeticError

190 Visual Smalltalk Enterprise Language Reference Exception Handling

All instances of Exception and its subclasses respond to the message description by returning a string that describes the actual exception. Your application may have its own exception conditions, distinct from those provided with Visual Smalltalk. To identify the exception, create a subclass of Exception or Error, as appropriate. If special handling is required for the exception, you will have to define a handler for it, as described in the following sections. The default handling is often enough, at least during development. The occurrence of an exception normally causes Visual Smalltalk to discard the work in progress. Sometimes a method does something that requires a subsequent action, regardless of whether or not an exception occurs. In that case, use the ensure: mechanism described earlier. Handling Exceptions You may need to define an action other than the default action associated with an exception. To do so, you define an exception handler. An exception handler has two parts: the class of exception it is to watch for, and the block of code it is to execute when such an exception occurs. Exception handlers are defined using the on:do: message. For example, the following expression defines an exception handler for an attempt to divide by zero, and specifies that a message be printed in the Transcript: [x / y] on: ZeroDivide do: [Transcript show: 'zero divide detected'.] If a zero divide error occurs while evaluating [x / y], the handler block (the argument to do:) is evaluated, causing the message to be written to the transcript. When created exception handlers for you application, you should be as specific as makes sense in naming the exception that the handler responds to. For example, it may be reasonable in some contexts to trap any error, without being any more specific than that. An expression like this then makes sense: [... some work ...] on: Error do: [Transcript show: 'An error occurred'; cr.]

Visual Smalltalk Enterprise Language Reference 191 CHAPTER 7 Handling Exceptions

The information returned is minimal, but may be enough. You probably do not want to handle any exception that occurs, however, so do not use an expression like this: [... some work ...] on: Exception do: [Transcript show: 'An exception occurred'; cr.] Exception is too general a category, and your application will respond to anything, including signals to Notification that have no effect on your application. An exception handler normally completes by returning the value of the handler block in place of the value of the receiver block. The above example, therefore, would return the Transcript, which might not be terribly useful. Suppose we want to return the value 0 when a division by zero occurred. We could then rewrite the expression as: [x / y] on: ZeroDivide do: [0] This could be used in some such code as the following: fudgeFactor := [x / y] on: ZeroDivide do: [0]. If, instead of returning a value, we want to exit the current method, we can place an explicit return within the handler block: fudgeFactor := [x / y] on: Error do: [^'uncomputable']. In the last example, we specified Error as the exception to be handled instead of ZeroDivide. When we specify an exception class to an exception handler, it will handle exceptions of the specified class, and also exceptions that are instances of subclasses of the specified class. ZeroDivide is a subclass of ArithmeticError, which is a subclass of Error. Therefore, an attempt to divide by zero or any other error that occurs while evaluating x/y causes the enclosing method to return the string uncomputable. Sometimes an exception handler needs to obtain information about the specific exception that it is dealing with. This can be accomplished by using a single argument block as the exception handler:

192 Visual Smalltalk Enterprise Language Reference Exception Handling

[x / y] on: Error do: [:theException | Transcript show: theException description. ^'uncomputable']. The instance of the class of exception that occurred is passed as the argument to the handler block. In the above example, the exception object could be an instance of ZeroDivide or an instance of ArithmeticError or an instance of Error. The message description is used in the above example to display a message in the Transcript. Signaling Exceptions Most of the exceptions that you need to deal with are detected by code within the standard Visual Smalltalk class library. Occasionally, however, you may need to write a new method to signal the occurrence of an exception—particularly if you have also created a new class of exceptions. An exception is signaled by sending the message signal to the class that defines the exception. For example: Error signal creates an error exception. If an active handler exists—that is, if a handler has been defined to deal with the Error exception—it is executed. Otherwise, the default handler is executed. It is often useful to provide a textual description of the problem when signaling an exception. You can do this using the message signal:. Warning signal: 'the disk is almost full' The argument string to signal: is incorporated into the value returned when the message description is sent to the resulting exception object. Exception Sets and Filters Occationally it is necessary to establish an exception handler to handle several signals that are not necessarily related in a hierarchical manner. This may be accomplished by specifying a list of exceptions in a handler. For example: [do some work] on: ZeroDivide, ControlError, Warning do: [whatever]

Visual Smalltalk Enterprise Language Reference 193 CHAPTER 7 Handling Exceptions

If any exception in the list, or any subclass of a listed exception, occurs, the handler block is acitivated. Such a list of exception is called an exception set. Another useful feature is the ability limit a handler to exceptions whose description match a particular pattern. For example: [do some more work] on: (Error says: 'OS Error:*') do: [work ] The message says:, when sent to an exception class, creates an exception filter. Exception filters may be used in conjunction with exception sets: [time to play] on: (Notification says: 'action 1') , (Notification says: 'action 2') do: [play] Resumable and Nonresumable Exceptions A handler block normally completes by executing the final statement of the block. The value of the final statement is then used as the value returned by the exception handler. Exactly where control is returned with that value, however, depends upon whether an exception is resumable or not. A nonresumable exception returns from the on:do: expression that created the handler block. However, a resumable exception returns from the message that signaled the exception. It is so called because it resumes execution rather than returning from the exception. Resumability is an attribute of an exception, not of an exception handler. Most exceptions that are subclasses of Error are nonresumable and therefore do not return to the method that signaled the exception. However, the default behavior for Notification, Warning, and some other exceptions is to return from the signaling message after executing the active handler for the exception. This is accomplished by returning the value returned by the exception handler as the result of the signal or signal: method: Warning signal: 'Low memory, save files!' "returns 1" For example, the following expression returns 5 as the value of the on:do: message because the signaled exception is an instance of Error, which is nonresumable: ( [Error signal] on: Exception do: [5]) "returns 5 here"

194 Visual Smalltalk Enterprise Language Reference Exception Handling

The next expression, however, returns 5 as the value of the signal message because the signaled exception is an instance of Notification, which is resumable: ([Notification signal "returns 5 here"] on: Exception do: [5]). The following two methods illustrate the flow of control in both cases. As you read them, bear in mind that Notification is a resumable exception, and Error is a nonresumable exception. method1 "Test exception behavior" [self method2] on: Exception do: [Transcript show: 'The exception was ']. Transcript show: 'nonresumable.'; cr method2 "Signal both a resumable and a nonresumable exception"

Notification signal."resumable" Transcript show: 'resumable.'; cr. Error signal."nonresumable" Transcript show:'This line never prints'; cr Figure 7-1 illustrates the flow of control (from left to right and down to up) for this example.

Visual Smalltalk Enterprise Language Reference 195 CHAPTER 7 Handling Exceptions

Figure 7-1: Flow of Control for Resumable and Nonresumable Exceptions

Transcript show: 'The exception was ' 8 7 : Transcript show : 'resumable.'; cr 9 12 6 11 Notification 10 method2 13 Error signal signal 5 14 4 (self method2) : value : 15 3 : Transcript show: : 'The exception was '

2

on: do:

1

method1 16

Transcript show: 17 'nonresumable.'; cr

When both methods complete, the Transcript looks like this: The exception was resumable. The exception was nonresumable. The last line in method2 occurs after the expression that signals an Error. Because instances of Error are nonresumable, this line will never execute, and the self-descriptive line This line never prints will never appear.

196 Visual Smalltalk Enterprise Language Reference Exception Handling

An instance of an exception can be explicitly tested to determine whether it is resumable by sending it the message isResumable. In the following example, the exception handler returns either 5 to the signaler or 10 from the on:do: message, depending upon whether the exception class is defined to be resumable or nonresumable: [ someExceptionClass signal ] on: Exception do: [:theException| theException isResumable ifTrue: [5] ifFalse: [10]] Most exception classes specify whether they are resumable or nonresumable on a class basis. However, it is possible for an exception class to specify whether or not each signaled exception is resumable. In order to define a class that can behave this way, implement the method isResumable for the class so that the method tests for the appropriate conditions. It can then return true under some circumstances and false under others.

NOTE: Signaling a resumable exception while evaluating the protected block of an ensure: or ifCurtailed: message does not cause the cleanup block to be executed, because execution of the protected block will be resumed instead of terminated.

The Exception Environment If an exception is signaled while executing the argument to the do: keyword in another exception handler, the specific exception handler that will handle the new exception is determined by the exception environment. The exception environment is an ordered list of active handlers. Each Smalltalk process has a distinct exception environment. When a new process begins, the list is empty. Whenever an on:do: statement is encountered and its receiver block is executed, a new exception handler is added to the beginning of the list. The entry to this list consists of the on:do: statement. When control returns from an exception handler, it is removed from the list. You can think of the list as a last-in, first-out stack. The figure below illustrates a hypothetical exception environment.

Visual Smalltalk Enterprise Language Reference 197 CHAPTER 7 Handling Exceptions

Figure 7-2: An Example Exception Environment

newest or innermost

C ontrolError direction of search

Warning

Error

ZeroDivide

oldest or outmost

The exception environment above was constructed by first creating a handler that read: on: ZeroDivide do: [someHandlerBlock] The next handler specified an Error exception, the next a Warning, and the most recent handles a ControlError. When an exception is signaled, the exception handling system sends a message to the first entry in the list to determine if it handles the specific exception generated. The first exception handler encountered that can handle the signaled exception does so. Now suppose that we are executing code in the exception environment illustrated above, and a ZeroDivide error is signaled. The first active exception handler handles a ControlError, so it is not executed. The next handles a Warning, so it is not executed either. The third handles an Error, which is a superclass of ZeroDivide. It therefore can handle the ZeroDivide exception, and does so. The Error exception handler executes its do: block, thereby creating a new exception environment of its own. In this case, the new exception environment has only a ZeroDivide handler in it, because that was the only handler created before the Error handler.

198 Visual Smalltalk Enterprise Language Reference Exception Handling

When a handler block is executed, the exception environment is trimmed to include only those active handlers created before the handler that is executing. These older handlers constitute the active handler’s exception environment. In other words, the active handler’s exception environment is the exception environment as it was at the time that the on:do: message was sent. If the error handler resumes, the original exception environment is restored. Otherwise, it is discarded. If no handler is found for an exception by searching the exception environment, the defaultAction method for the exception is executed. When a default action method is executed, the exception environment is the same as it existed at the point the exception was signaled. Exiting Handlers Explicitly Occasionally you may need to manage the flow of control among multiple exception handlers. Any of several messages can be sent to the argument of a handler block to allow you to conclude processing of the handler block before it reaches its final statement, or to interrupt its processing and return to it later. These messages are: exit:, resume:, return, return:, retry, retryUsing:, resignalAs:, pass, or outer. The message exit: causes its argument to be returned as if it were the value of the final statement of the handler block. The following two handlers therefore have exactly the same behavior: [Error signal] on: Exception do: [5]. [Error signal] on: Exception do: [:theException| theException exit: 5]. The message exit: is useful for conditionally exiting a complex handler block. For example: [Error signal] on: Exception do: [:exception | exception isResumable ifTrue: [exception exit: 5]. Menu message: 'Nonresumable exception'] If the exception is resumable, exit: restores the original exception environment. Otherwise, the exception environment is trimmed to the active handler’s exception environment.

Visual Smalltalk Enterprise Language Reference 199 CHAPTER 7 Handling Exceptions

If the argument of a handler block is a resumable exception, the message resume: can be used instead of exit:. For a resumable exception, resume: behaves in exactly the same manner as exit:. Sending resume: to a nonresumable exception causes the system to signal a ControlError. The message resume: therefore restores the original exception environment. The messages return and return: are another alternative to exit:. These messages cause the handler block to return from its on:do: message. The value returned is the argument of return:—or undefined if return is used. When sent to a nonresumable exception, return: has the same effect as exit:. When sent to a resumable exception, return: forces control to return from the on:do: message instead of from the signal message that created the exception. Thus, return: can simulate the effect of a nonresumable exception when an exception is in fact resumable. The messages return: or return therefore trim the exception environment to the active handler’s exception environment. Another way to exit a handler block is with the retry message. This message terminates the handler block and tries again to evaluate the receiver of the on:do: block. Any cleanup blocks created using ensure: or ifCurtailed: are executed before retrying the evaluation, whether they were created by the original evaluation of the receiver block or by the handler block. For example, the following method tries again after a division-by- zero error: [^ x / y] on: ZeroDivide do: [:theException| "make the divisor very small but > 0" y := 0.00000001. theException retry] The message retry therefore trims the exception environment to the active handler’s exception environment when it retries execution. The message retryUsing: is similar to retry, but instead of evaluating the original receiver block, the argument to retryUsing: is evaluated instead. For example:

200 Visual Smalltalk Enterprise Language Reference Exception Handling

[self doTaskQuickly] on: LowMemory do: [:theException| theException retryUsing: [self doTaskEfficiently]] The message retryUsing: also trims the exception environment to the active handler’s exception environment when it retries execution. The message pass can be used inside a handler block to terminate the handler block and execute any enclosing handler blocks for the current exception. For example: [n / m] on: ZeroDivide do: [:theException| "0/0 = 1; otherwise signal a ZeroDivide exception" theException dividend ~= 0 ifTrue: [theException pass] ifFalse: [theException return: 1] The message pass sets the exception environment to the environ- ment of the handler to which it passes control. In this example, the programmer has decided to handle the case of 0 / 0 specially. If the dividend is anything other than zero, however, control passes to the ZeroDivide exception. Control never returns to the sender of a pass message. The message outer can be used to execute enclosing handlers, after which control ordinarily returns to the first handler. When sent to an exception from within a handler block, outer finds and executes any enclosing handler for the exception. If the enclosing handler resumes, control returns from the outer message. If the enclosing handler returns or retries, control does not return from the outer message. Instead, execution continues as it would in any other case using the return, return:, retry, or retryUsing: messages. If the enclosing handler exits, control returns to the outer message if the handler is resumable. Otherwise, it does not. For example: [self someAction] on: Warning do: [: theException| self initialWarningAction. "let any enclosing handlers deal with it" theException outer. self finalWarningAction]

Visual Smalltalk Enterprise Language Reference 201 CHAPTER 7 Handling Exceptions

The message outer sets the exception environment to the environment of the handler to which it passes control. When control returns, the original handler’s exception environment is restored. Translating Exceptions Occassionally, an exception handler may need to translate one exception into another exception. For example, a low-level operating system error exception might need to be translated into a higher level user exception. Care is required to avoid executing the wrong handler. The reason is that the exception environment within the handler signalling the low-level exception is not necessarily the same as the exception environment signalling the high-level exception. This problem is solved by using the message resignalAs: instead of signal within the handler block. For example: [low-level I/O] on: OperatingSystemException do: [ex| ex errorCode = -213 ifTrue: [ex resignalAs: EndOfFile new] ifFalse: [ex resignalAs: (Error new messageText: 'OS Error']] The message resignalAs: aborts the current exception handler, restoring the exception and execution environments to its original state, as it existed when the exception that is the reciever of resignalAs: was originally signaled. (Note that this may cause the execution of ensure: or ifCurtailed: blocks). After the environments are restored, the exception that is the argument to resignalAs: is signaled. This causes the argument exception to function as if it had been originally signaled in place of the receiver.

202 Visual Smalltalk Enterprise Language Reference CHAPTER 8 Help Manager Visual Smalltalk allows you to access and use the native operating system help facility from an application. We assume that you are familiar with creating help files for the target operating system platform. For information on developing help files, refer to operating system Software Development Kit documentation. User Interface To understand the Help Manager user interface, install the Puzzle 15 sample program in the Services Browser. Once you start the program, do the following: 1 Press the F1 key (the Help key). A Help window displays extended on-line help for Puzzle15. A Help menu has been added to the end of the menu bar. 2 Select the Help Contents menu item. It lists all of the help topics available for Puzzle15. 3 Press and hold the left mouse button over the Puzzle menu in the menu bar and press the F1 key. A help window displays, describing the Puzzle menu commands. Then, drag the mouse to the Scramble menu item, press the F1 key, and a Help window displays that describes Scramble menu item. 4 Choose the Select Colors... menu item from the Puzzle menu, and a dialog window opens. Press F1 without selecting anything in the dialog window. A help window displays the Help window for the whole dialog window. Next, select one of the combo boxes and press F1. An appropriate Help window displays.

Visual Smalltalk Enterprise Language Reference 203 CHAPTER 8 Help Manager Programming Interface To use the system help facilities you need to: • Create the help files • Create an instance of HelpManager for the help files • Make appropriate calls to access context sensitive help Adding Help To an Application To include on-line help in your application: 1 Create and compile the help file. This involves creating a document file in .RTF format (for Windows) or .IPF format (for OS/2), and compiling the file into help format. Consult the system help compiler documentation for the details. Help panels, or topics, are identified by a context string. Context strings in the application are identified according to the following: • The context string of a menu is its menu title. • The context string of a menu item is its selector. • The context string of a subpane is its name (defined by the getContents event or by sending the setName: message to it). • The context string of a DialogBox is defined by the application sending the extendedHelpPanelId: message to the HelpManager instance before opening the DialogBox or DialogTopPane. • The context string of a control in a DialogBox is the name of the item as specified in the ItemIds dictionary of the subclass of DialogBox. • The context string of TopPane and its subclass is the HelpIndex topic. This default topic can be changed by sending the extendedHelpPanelId: message to the helpManager instance.

204 Visual Smalltalk Enterprise Language Reference Programming Interface

2 In the open: method for your application, create an instance of HelpManager. Create an instance of HelpManager before you do self openWindow. Then, create an instance of HelpManager in your open method by sending the message for:title:file: to HelpManager. For example: hm := HelpManager for: self mainView title: '15 Puzzle Help' file: 'puzzle15.hlp'.

"On Windows, include this line also" hm mapDictionary: aMapDictionary In this example, it is assumed that the application is a subclass of ViewManager and it has only one view. The for:title:file: message needs to be sent once for each view, passing that view as the parameter of for:. While each view of the ViewManager has a different HelpManager associated with it, the hlp file associated with each of them may be the same or different, depending on the needs of the application. For Windows help, use the following message to create the map dictionary: StringDictionaryReader class>>createIdDictionary: aFileName This message creates a string identifier dictionary from a text file aFileName with dictionary keys being string identifiers and values being integer values. Contents of aFileName must be in standard C language header file (.H) format. Note that aFileName should be the include file you use in your Help project file (.hpj). OS/2 Dialog Windows On OS/2, if your application has dialog windows, you can use the HelpManager class method for:title:file:dialogs:, and include an array of their dialog id’s. For the purpose of using help to associate an id with the dialog window, the class that implements the dialog must have a class method called windowId, which must answer the id of the dialog window.

Visual Smalltalk Enterprise Language Reference 205 CHAPTER 8 Help Manager

For example, Puzzle15 uses two dialog windows. One is implemented by class Prompter and the other is implemented by class Puzzle15Colors. Prompter creates the dialog window using a resource, Puzzle15Colors does not use resources. Both classes implement the class method windowId. To create a HelpManager for Puzzle 15, in the application’s open method, send the class method for:title:file:dialogs: to HelpManager. Note the last argument is an array of the two dialog window id’s. HelpManager for: self title: '15 Puzzle Help' file: 'examples\puzzle15\puzzle15.hlp' dialogs: (Array with: Prompter windowId with: Puzzle15Colors windowId). The instance of HelpManager created above covers the Puzzle15 and its two dialog windows, and the dialog windows do not create instances of HelpManager themselves. If the dialog window is created without using a resource file, that is, it is a subclass of WindowDialog, you also have the option of creating its own instance of HelpManager. You can do so in the same manner you would for any other subclass of ViewManager. In the open method, send a for:title:file class method to HelpManager, and Visual Smalltalk will take care of the rest. This is particularly useful if you are creating a dialog window as an independent application by itself. In addition to the HelpManager instance your application sets up, there is a help event supported by TopPane, DialogTopPane, and SubPane. When the F1 key is pressed, if either the SubPane that has the focus or its TopPane handles the help event, the registered selector is sent and normal help processing does not proceed. If neither the SubPane nor the TopPane handles the event, the associated help manager (if any) processes the help request. You can use this mechanism along with the displayHelp: instance method to perform your own help processing before handing contorl off to the HelpManager instance.

206 Visual Smalltalk Enterprise Language Reference Programming Interface

Responding to User Requests Use the following HelpManager messages to interactively display help panels: for: aWindow title: aString file: aFileName Answer an instance of the receiver initialized for aWindow with aString as its title and whose Help file is in aFileName (a .HLP file). Under Windows, aString is ignored. for: aWindow title: aString file: aFileName dialogs: aCollection Answer an instance of the receiver initialized for aWindow with aString as its title and whose Help file is in aFileName (a .HLP file). aCollection must contain the dialog box ids for the application. Under Windows, aString and aCollection are ignored. for: aWindow title: aString file: aFileName dialogs: aCollection aboutDlgClass: aboutDlg Answer an instance of the receiver initialized for aWindow with aString as its title and whose Help file is in aFileName (a .HLP file). aCollection must contain the dialog box ids for the application. aboutDlg is a class that implements an open instance method creating the About dialog. Under Windows, aString and aCollection are ignored. displayHelp: anId Brings up the help for the topic defined by anId. extendedHelpPanelId Answer the default topic. extendedHelpPanelId: anId Set the default topic to anId. map: aDictionary (Windows only) Set the receiver’s map dictionary. The keys are the context strings defined in the .RTF help file. The values are integer defined in the include file used by the help compiler. map (Windows only) Answer the receiver’s map dictionary. The keys are the context strings defined in the .RTF help file. The values are integer defined in the include file used by the help compiler.

Visual Smalltalk Enterprise Language Reference 207

CHAPTER 9 Smalltalk Link Libraries Overview A Smalltalk link library (or Smalltalk library) is a file containing objects that can be bound, or linked, to a Visual Smalltalk image. While Smalltalk libraries can contain any objects, they primarily contain classes and methods. Smalltalk libraries provide a facility for partitioning Smalltalk classes into small collections, rather than having to store all objects in a large image. The smaller libraries are then bound to an image and their contents accessed like any other object. A Smalltalk library can be either statically or dynamically bound to a Visual Smalltalk image. Dynamic binding allows a program to gain access during runtime to objects that are not in the application image. A Smalltalk library can also be unbound during runtime, freeing memory resources. Any Smalltalk object can be put into a Smalltalk library. A library typically contains Smalltalk classes, including all the methods in those classes, but can also contain individual methods, globals such as pool dictionaries, and so on. Smalltalk libraries are “pluggable,” or individually replaceable, making maintenance and enhancement releases as simple as replacing a file. Cross Platform Portability Smalltalk link libraries use a format that is identical for on Windows and OS/2 platforms, making the same library usable on either system. Accordingly, Smalltalk libraries are portable between operating system platforms to the extent that the objects they contain are portable. To ensure the portability of a Smalltalk library, do not use operating system specific API’s. You can use platform specific features as long as you employ the Visual Smalltalk portable protocol for these features. Portable protocols are more prominent in release 3.0 than they had been in previous releases. The new drag/drop model, for instance, is portable, as are also a large number of window and control protocols. There are still a few operating system specific protocols

Visual Smalltalk Enterprise Language Reference 209 CHAPTER 9 Smalltalk Link Libraries

left in the system for applications that require them, generally indicated in the method comments or by location in the class hierarchy. Accessing Smalltalk Link Libraries Visual Smalltalk gains access to the objects in a SLL by binding the library file to the running image. You can then access and use those objects just like any other object in the image. To bind a Smalltalk library during development, you can use the File/Install menu option and select the file, or evaluate this expression, substituting the file name: SmalltalkLibraryBinder bindTo: 'filename.SLL' The library file must be on the system search path before being bound to the image. The directory containing an image file is always on the search path for that image. To view the contents of the library, inspect the expression: SmalltalkLibraryBinder contentsOf: 'filename.SLL' To test for the presence of a Smalltalk library, use: SmalltalkLibraryBinder isBound: 'filename.SLL' To get a collection of all bound libraries, use: SmalltalkLibraryBinder bound When the objects in a Smalltalk library are no longer needed or must be replaced, you unbind the library. Once unbound, the system no longer has access to the objects in that library. To unbind a Smalltalk library, evaluate: SmalltalkLibraryBinder unBind: 'filename.SLL' There are several other methods for binding a SLL to an image that are useful during development but are especially needed for a runtime application. These fall into three categories: • Static binding • Binding at startup • Dynamic binding during runtime

210 Visual Smalltalk Enterprise Language Reference Accessing Smalltalk Link Libraries

Statically Binding a Smalltalk Link Library Once you bind a Smalltalk Link Library to an image and save the image, that version of the SLL is statically bound to the image. The SLL must be present on the system search path when that image is started, in either a runtime or development environment. The SLL can be either in the Visual Smalltalk directory or in a directory set in the system PATH statement. If the SLL is missing, or the wrong version of it is found, Visual Smalltalk will not start up. To unbind the SLL from the image, use the unBind: message. Make sure all objects referring to that library are removed from the system and that memory resources have been released (see Unbinding and Reclaiming Memory below). Then resave the image. You can then bind another version of the library or leave it unbound. As long as the image is not saved while a library is bound, Visual Smalltalk does not require it to start up. Binding Smalltalk Link Libraries at Startup Rather than have Smalltalk libraries statically bound to an image, it is often preferable to bind them to the image at startup. One advantage is that it is easier to replace a library, for example to update it. Since the image is not bound to a particular version of a library, all you need to do is replace the old file and startup the image. The new version will bind while Smalltalk is starting. There are two ways to bind an Smalltalk library to the image during startup: • List the Smalltalk libraries in the binding list file for the image • Include the Smalltalk libraries in the startUpApplication method of the NotificationManager class SLL Binding List File While starting a runtime image, Visual Smalltalk checks the system search path for a file with the same name as the image but with a “.BND” extension. While starting a development image, Visual Smalltalk looks for VDEVW.BND on Windows or VDEVO.BND on OS/2. If such a file is found, Visual Smalltalk reads from it the names of Smalltalk libraries to bind to the image. The binding list file is a plain text (ASCII) file with the name of one Smalltalk library on each line. The Smalltalk library name may be either the actual file name or a logical library name. If a logical library name is used, there must be an accompanying Smalltalk library Map file (described below).

Visual Smalltalk Enterprise Language Reference 211 CHAPTER 9 Smalltalk Link Libraries

startUpApplication Method Rather than maintain a separate file, you can include binding expressions for Smalltalk libraries in the startUpApplication method. This is appropriate only for runtime applications since that is when this method is evaluated. In this method, add as many expressions as needed to bind the needed libraries: SmalltalkLibraryBinder bindTo: 'name.SLL' The startUpApplication method is discussed the application delivery chapter of the Visual Smalltalk Enterprise User’s Guide. Dynamically Binding and Unbinding a Smalltalk Link Library The ability to dynamically bind and unbind Smalltalk Libraries during the run of an application is of great advantage, especially for large applications. By selectively binding and unbinding libraries, an application can exercise a large degree of control over the amount of memory it requires. Once a library has been unbound, its memory resources are released and can be garbage collected by the system. Bind a Smalltalk library by sending the bindTo: message to the SmalltalkLibraryBinder class: SmalltalkLibraryBinder bindTo: 'filename.SLL' Make sure the library is in the Visual Smalltalk directory or on the system search path set by the system PATH statement. Similarly, unbind a library by sending the unBind: message: SmalltalkLibraryBinder unBind: 'filename.SLL' When you unbind a Smalltalk Library, the contents of the library are removed from the system. The memory that had been occupied by the library is garbage collected after a short delay, unless there are objects remain that refer to objects in the library. (See Unbinding and Reclaiming Memory below.) Unbinding and Reclaiming Memory Visual Smalltalk unbinds Smalltalk libraries in two stages. First, it removes the contents of the library, all the classes, methods, globals, etc., from the environment; they are no longer available to the programmer or the application. Second, Visual Smalltalk attempts to recover all the memory occupied by the library while it was bound.

212 Visual Smalltalk Enterprise Language Reference Accessing Smalltalk Link Libraries

However, Visual Smalltalk does not attempt to recover the memory occupied by an unbound library if there are persisting objects outside the library pointing at objects inside the library. For example, if an application creates instances of a class that is defined in the library, those instances point directly into the memory occupied by the library. Releasing this memory while the persisting objects are still pointing to it would cause a system crash. To avoid crashes and to ensure that a runtime application which dynamically binds and unbinds libraries runs correctly, Visual Smalltalk does not release memory in this case. By not releasing the memory, two potential problems are presented: • Visual Smalltalk runs the risk of running out of memory if such a library is repeatedly bound and unbound. It is the responsibility of any application that binds and unbinds Smalltalk libraries to ensure that all objects pointing into a library are destroyed before unbinding the library. • If you save the image while this memory is still in use, the unbound library becomes statically attached to the image and must be present in order for the image to start up, as is usual for statically bound libraries. If you try to save an image with an unbound but still unreleased library, a dialog warns you of the situation and allows you to either cancel or proceed with saving the image. Unbinding a library that still has external objects pointing into it is a programming bug in the application doing the binding and unbinding. While it is not a common bug, you may need to deal with it if your application does very many binds and unbinds. Identifying Objects Pointing to an Unbound Library Bound libraries are contained in a the bound library list returned by sending the bound message to SmalltalkLibraryBinder. When a library is unbound libraries but its memory is not yet released, it is indicated in the bound library list by a nil. If there are no objects pointing into an unbound library, then the next time SmalltalkLibraryBinder compact is sent, the memory for the unbound library is released and the nil is removed from the list. If there are objects pointing into an unbound library, compact does not remove the nil. To determine if there are any external objects pointing to an unbound library, first send the compact message and then send the unboundCount message to SmalltalkLibraryBinder:

Visual Smalltalk Enterprise Language Reference 213 CHAPTER 9 Smalltalk Link Libraries

SmalltalkLibraryBinder compact; unboundCount This returns the number of nil entries in the list. If there are any, use the following methods to identify the remaining objects: Identify the remaining “live” objects in the library by sending: SmalltalkLibraryBinder liveObjectsIn: anInteger where anInteger is the position of the library nil entry in the bound library list. This message answers a collection of the live objects in the library. This method may return a large portion of the library, because once one object is pointing into a library, at a class for instance, then all the objects that object points to are also alive. You will have to examine the contents to determine which objects need to be destroyed. To identify the objects pointing into the unbound library, send: SmalltalkLibraryBinder allReferencesTo: anInteger where anInteger is the position of the library nil entry in the bound library list. This message answers a collection of all objects containing pointers into the library. This method should assist you in figuring out why there are objects pointing into the unbound library. Smalltalk Library Logical Names and Map Files There are a number of situations in which it is useful to refer to Smalltalk Libraries indirectly by logical name, or alias, rather than directly by file name. Visual Smalltalk supports using logical library names through a map file. Logical library names can be used in any expression referring to a Smalltalk library (such as bindTo: and unBind: messages) and in the binding list file. The map file is a plain text (ASCII) file. The file name must be the same as the image file name, but with a “.MAP” extension. For a development image, the file name is VDEVp.MAP. Each line in the file contains one mapping in the format: logical_name = file_name The logical name can be any character string, including spaces.

214 Visual Smalltalk Enterprise Language Reference Accessing Smalltalk Link Libraries

SmalltalkLibraryBinder Public Protocol Class Methods attemptBindTo: aLibraryName Attempt to bind to aLibraryName. Answer true if successful, false if not. bindTo: aLibraryName Bind to aLibraryName, which can be either a logical name or a file name. Answer the Smalltalk library object. bound Answer the collection of bound Smalltalk libraries. compact Recover the memory from unbound Smalltalk libraries. contentsOf: aLibraryName Answer a dictionary describing the contents of aLibraryName. isBound: aLibraryName Answer true if a library named aLibraryName is already bound. liveObjectsIn: anInteger Answer a collection of the live objects in the library identified by anInteger, which indicates a position in the collection returned by bound. named: aLibraryName Answer the bound Smalltalk library named aLibraryName, or nil if the library is not bound. nameMap Answer the mapping from logical Smalltalk library names to physical file names. nameMapAt: aLogicalName put: aFileName Register a mapping from aLogicalName to aFileName, so that if a request is made to bind aLogicalName, then aFileName will be bound. unBind: aLibraryName Unbind the Smalltalk library named by aLibraryName. unboundCount Answer the number of unbound libraries for which memory has not been garbage collected. This is the number of instances of nil in the collection returned by bound.

Visual Smalltalk Enterprise Language Reference 215 CHAPTER 9 Smalltalk Link Libraries

versionOf: aLibraryName Answer a string listing the version date and time of the library in aLibraryName. Instance Methods abortUnbind Use this message to prevent unbinding a library in response to the aboutToUnbind event. bind Bind the receiver. Answer the bound Library. file: aLibraryName Specify the file name for the Smalltalk library. Events libraryBound Triggered by the SessionModel when a library is bound. aboutToUnbind Triggered by SmalltalkLibrary just before unbinding a library. Send abortUnbind to veto the unbind. Smalltalk Library Builder You create a Smalltalk Library using the Smalltalk Library Builder. This procedure creates a Smalltalk Library containing the classes and methods you specify. Install the Smalltalk Library Builder by selecting Smalltalk Library Builder in the Services Browser. Using Smalltalk Library Builder Building a Smalltalk Link Library is a simple process of specifying its contents and its file name. You can also specify special handling requirements, such as whether or not to include source code, and whether to produce a report of references to other bound Smalltalk Libraries (imports). When you specify a class to include in a library, Smalltalk Library Builder includes the following objects: • The class object • The metaclass • Class variables • Method dictionary • All the methods

216 Visual Smalltalk Enterprise Language Reference Smalltalk Library Builder

For each method, Smalltalk Library Builder includes the following: • The method’s compiled code • Literals, including pool dictionary variables • Source code (optional) If a method refers to a class that is not in the library being built (for example, if a method has a line of code that contains the expression String new), class String is not included in the library. Rather, that class is treated as an imported object, and the Smalltalk Library Builder adds an import (or pointer) representing that class to the library. Similarly, if a method refers to a global variable, an import for that global is added to the library. Building Smalltalk Libraries You build a Smalltalk library by writing a script, an expression that you can evaluate to create the library. The script can be executed repeatedly to rebuild the library as you make changes to its content. Consider the following script: | sll | sll := SmalltalkLibraryBuilder new: 'test'. sll description: 'Smalltalk Library Test'. sll windowFeedback. sll add: Test. sll addGlobalNamed: #TestGlobal. sll add: ( UndefinedObject compiledMethodAt: #test ). sll writeFile. ^sll The script works as follows: sll := SmalltalkLibraryBuilder new: 'test'. Creates an instance of SmalltalkLibraryBuilder, and opens a new file, named TEST, to store the new library. sll description: 'Smalltalk Library Test'. Sets the description in the library file header. sll windowFeedback. Opens a blank TextWindow into which feedback will be written. sll add: Test.

Visual Smalltalk Enterprise Language Reference 217 CHAPTER 9 Smalltalk Link Libraries

Adds class Test to the library. This adds the class, the class’s MetaClass, class variables, and all the methods in the class, both class methods and instance methods. Source code for all the methods is also included. This does not add the class’s subclasses. sll addGlobalNamed: #TestGlobal. Adds the global TestGlobal to the library. sll add: ( UndefinedObject compiledMethodAt: #test ). Adds the individual method test from UndefinedObject. sll writeFile. Writes the Smalltalk Library file TEST.SLL. This ends the script, and returns the new library. Smalltalk Library Builder Options Including and Excluding Source Code Smalltalk Library Builder allows you to selectively include and exclude source code. Source code that is included can be contained either within the library or in a separate source file. The simplest way to include or exclude source code is to send the includeSource: message, specifying either true or false: sll includeSource: false. sll includeSource: true. This message sets the source inclusion option generally, for all following objects added to the library, until the option is changed or overridden by another source inclusion message. The message can be sent as many times as necessary, turning inclusion on and off as required. You can override the general source inclusion option for individual methods by using the addMethod:includeSource: message: sll addMethod: ( aClass compiledMethodAt: #aMethodName ) includeSource: aBoolean. Using this message you can include the source (true) while source is generally excluded, or exclude the source (false) while source is generally being included from the library.

218 Visual Smalltalk Enterprise Language Reference Smalltalk Library Builder

Including and Excluding Subclasses The add: and addClass:includeMethods: methods add only the class named. To include subclasses, you can either add them individually or, to add all subclasses, use this expression: aClass withAllSubclasses do: [:class | sll add: class ]. to include all methods, or aClass withAllSubclasses do: [:class | sll add: class includeMethods: false]. to exclude all methods. Including and Excluding Methods The add: method adds an object to the Smalltalk library. Any object can be added using this message. If the object is a class, all of its methods are added as well. You can exercise more control over the methods included by using the addClass:includeMethods: method. sll addClass: aClass includeMethods: methods. The second argument, methods, is either a boolean or a list of methods. If false, all methods are excluded from the library, and if true, all methods are included. If the argument is a collection of message selectors, only those methods named are included in the library. You can add individual methods with add: by naming the method as a compiled method of its class: add: ( class compiledMethodAt: #methodName ) bindAction and unBindAction You can specify an action to perform just after the library is bound or just before it is unbound. The bind action allows you to specify actions to perform when the library is bound, such as initialize variables or register handlers for events like startup (triggered by SessionModel). Typically, you would provide a class method to do all this initialization, then set that method as the bindAction for the library. For example, suppose you build a library containing class Foo, which needs to initialize some information each time the image is started. Your method would look something like this:

Visual Smalltalk Enterprise Language Reference 219 CHAPTER 9 Smalltalk Link Libraries

justBound "The library was just bound." | sessionStartupAction | sessionStartupAction := Message receiver: Foo selector: #startup. sessionStartupAction evaluate. SessionModel current when: #startup evaluate: sessionStartupAction. Similarly, you can specify an action to perform just before the library is unbound: removeLibrary "Prepare to remove the library." SessionModel current removeActionsWithReceiver: Foo forEvent: #startup. Then, specify these actions in the library build script: sll bindAction: (Message receiver: Foo selector: #justBound). sll unBindAction: (Message receiver: Foo selector: #removeLibrary). SmalltalkLibraryBuilder Public Protocol Class Methods new Answer a new instance of the receiver. There is no file name, so the library is not written to a file. new: aFileName Answer a new instance of the receiver whose filename is aFileName. Note that that file name extension is not required; it is provided by Smalltalk Library Builder. Instance Methods Setup Messages Typically you send these messages before adding any objects. description: aString Set the description for the library being built. directory: aDirectory Set the directory for the resulting file.

220 Visual Smalltalk Enterprise Language Reference Smalltalk Library Builder fileName: aString Set the file name for the library being built. includeSource: aBooleanOrEvaluableAction Include source code or not for classes and methods added from now on. If the argument is an evaluable action, it is passed the method as an argument and should answer true or false. objectCountEstimate: anInteger Provide an estimate of the number of objects that will be in the receiver, so that dictionaries can be initialized with an appropriate starting size to avoid growing and therefore speed up the building time. sourceInFile For those methods with source code, put the source code in the library file, as opposed to putting source in a separate file (see sourceSeparate). This is the default. sourceSeparate For those methods with source code, put the source code in a separate file, as opposed to putting source in the library file (see sourceInFile). The source file name has the same prefix with a “.SML” extension. windowFeedback Provide feedback in a text window. Set Contents These methods set the contents of the library . add: anObject Add anObject to the library being built. anObject is typically a method or a class. add: anObject named: aName Add a named object to the library being built. addClass: aClass includeMethods: includeMethods Add aClass to the receiver. If includeMethods is true, then include all the class’s methods. If includeMethods is false, then do not include any methods. If includeMethods is a collection of selectors, then only those methods will be included. If includeMethods is true or false and aClass is a class (not a metaclass), then the class’s metaclass is added to the receiver too. addGlobalNamed: aSymbol Add the named global to the library.

Visual Smalltalk Enterprise Language Reference 221 CHAPTER 9 Smalltalk Link Libraries

addImport: anObject fromLibrary: aLibraryName Add anObject as an import for the library being built, and indicate that anObject can be found in another library named aLibraryName. anObject is typically the association for a class or global variable. This allows specifying prerequisites for binding, telling SmalltalkLibraryBinder to ensure that anObject exists in the image when it is binding the new library, and if it does not exist, try binding aLibraryName first. addMethod: aMethod includeSource: aBoolean Add aMethod to the receiver. Include its source code if aBoolean is true. addPoolVariable: anObject named: variableName in: poolName Add the pool variable anObject named variableName from the pool named poolName to the library being built. bindAction: anEvaluableAction Set the action to be evaluated when the library is bound. remap: anObject to: anotherObject Change anObject to anotherObject in the library. unBindAction: anEvaluableAction Set the action to be evaluated just before the library is unbound. Build the Smalltalk Library writeFile Build the library, and write it to the file named in new:. interestingImports Answer a dictionary where the keys are the imports from the library and the value is a collection containing first the library the imported object is from and then a list of the objects which refer to the imported object (i.e. the objects that caused the imported object to be imported). Imported objects that are in the base Visual Smalltalk system are not included in this dictionary because they will always be present in the image the library is bound to. The objects included in this dictionary must exist in the image the library is bound to, so examine the interestingImports dictionary to make sure those objects will exist when the library is bound.

222 Visual Smalltalk Enterprise Language Reference Smalltalk Library Builder

Smalltalk Library Bind/UnBind Events When a Smalltalk library is bound, the current session model triggers the libraryBound: event. The event argument is the library that has just been bound. The message name can be sent to the argument to get the library name. If you want to know when a Smalltalk library is bound to the image, you can register an action for this event libraryBound:. For example: SessionModel current when: #libraryBound: send: #inspectNewLibrary: to: ImageWatcherClass. Similarly, when a Smalltalk library is about to be unbound, it triggers the aboutToUnbind event. The message abortUnbind can be sent to the library to stop the unbind from happening. The library triggers unbind after the unbind is complete.

Visual Smalltalk Enterprise Language Reference 223

CHAPTER 10 Object Filer Overview The Object Filer provides another mechanism in Visual Smalltalk for storing objects and exchanging them among images. You can store and exchange code by filing out the source code of classes and methods. The Object Filer provides an equivalent mechanism for storing and exchanging the data represented by objects in your image. You can perform three basic operations with the Object Filer: you can dump an object, load an object, and produce a report describing a binary filed object or its classes. Objects in binary form can be dumped to or loaded from a file, or the clipboard. The Object Filer generates an efficient binary representation of a complex object that retains object identities within the set of reachable objects: • Detects circular object structures and shared references within a network of objects and reconstructs them properly when the filed object is loaded. • Allows you to load objects into Visual Smalltalk applications that do not include the development environment. • Allows you to process classes in specified ways before you store them or after you load them. By implementing a dump or load method in a class, you can control the contents and form of the set of objects that are filed. Note that the Object Filer cannot store objects that represent host operating system resources such as handles, pointers, or external data structures, because such objects are only meaningful in the context of a single programming session. If the Object Filer encounters an object that it knows it cannot properly store or load, you are notified.

Visual Smalltalk Enterprise Language Reference 225 CHAPTER 10 Object Filer

The Object Filer and Smalltalk Libraries There are many similarities between Object Filer files and Smalltalk link libraries. Both allow you to separate objects from your image and store them permanently in a file. Both support exchanging objects between images by allowing you to install filed objects into a new image. However, there are also some significant differences: • Smalltalk libraries are primarily intended for use as an application delivery mechanism. They support delivery of both class code and data resources. The Object Filer is primarily intended for storing and exchanging data objects. It does not support filing out methods, since it is possible to exchange code using existing mechanisms (such as by filing out the source of a method or an entire class). • The Object Filer can be used to dump and load objects in a runtime application, whereas building Smalltalk libraries requires the development environment. • The Object Filer is a “lighter weight” mechanism for easily transferring working data to a co-worker or into a different image. When you load a filed object that you stored at some previous time or which has been given to you by someone else, it is possible for the environment in the loading image to be significantly different from the environment from which the original object was stored. The class of an object being loaded may not exist or its definition may have been changed since the object was filed out. The Object Filer detects missing classes and differences in class definitions between the source image from which an object was dumped and the target image into which an object is being loaded. When a discrepancy is detected, the Object Filer opens an interactive dialog in which you can indicate how to proceed, or cancel loading until you resolve the situation. Object Filer supports a protocol for class-specific dump preprocessing and load postprocessing. By implementing a dump or load method in a class, you can control the contents and form of the set of objects that are filed. Installing the Object Filer To install the Object Filer, select Object Filer in the Services Browser.

226 Visual Smalltalk Enterprise Language Reference Loading Objects

Storing Objects The following are the standard messages for storing an object: • To open a file dialog to specify the filename interactively, execute: ObjectFiler dump: anObject • To create or overwrite a specified file, execute: ObjectFiler dump: anObject newFile: aPathName • To append to a stream, execute: ObjectFiler dump: anObject on: aStream The set of objects reachable from the given root object is determined by recursively enumerating the contents of each object, starting at the root, until a terminal object is encountered. A terminal object is either: • A primitive data value (nil, true, false, or an instance of Integer, Character, or Symbol, or a byte-indexable object) • A unique object such as the value of the global variables MetaClass, Smalltalk, Notifier, Processor, Clipboard, and Display •A Behavior (a class or a metaclass) Terminal objects are stored in an efficient format that uses the appropriate instance existing in the image when the filed object is loaded into an image. Note that the Object Filer does not store objects that represent code or execution state, such as methods, classes, or processes. However, blocks can be stored (for example, sort blocks in a SortedCollection). Loading Objects The following are the standard messages for loading an object: • To open a file dialog to specify the filename interactively, execute: ObjectFiler load • To load a specified file into an already running image, execute: ObjectFiler loadFromPathName: aPathName

Visual Smalltalk Enterprise Language Reference 227 CHAPTER 10 Object Filer

• To read from the current position of a stream, execute: ObjectFiler loadFrom: aStream If a fatal error occurs during loading, the Object Filer returns nil and displays information about the problem. Using the Clipboard To copy objects to the clipboard instead of a file, evaluate an expression such as: Clipboard setObject: anObject where Clipboard is a global variable representing the single instance of the class ClipboardManager in the system, anObject is the object you wish to copy to the clipboard, and the message setObject: copies the specified object to the clipboard. Objects can also be pasted from the clipboard. To do so, evaluate an expression such as: Clipboard containsObject ifTrue: [Clipboard getObject] Clipboard is a global variable representing the single instance of the class ClipboardManager in the system. The message getObject retrieves the clipboard object if the message containsObject determines that the clipboard contains a Visual Smalltalk object. Resolving Class Definition Changes When loading objects from one image into another, two kinds of class definition problems can occur: • The source image included a class that the target image does not define. The object file includes an instance of the now undefined class. • The source image defined a class in a manner different from the target image. The object file includes an instance of the now differently defined class. Before loading, the Object Filer checks for these problems. If a missing class is detected, the Object Filer opens a dialog to inform you. If a modified class definition is detected, the Object Filer opens an object load map dialog that allows you to specify interactively how the stored instance is to be modified upon loading.

228 Visual Smalltalk Enterprise Language Reference Resolving Class Definition Changes

Missing Classes When a missing class is detected, a dialog tells you the name of the missing class. If you cannot immediately resolve the discrepancy, you can cancel loading the object. A class could be missing for either of two reasons: • You have renamed a class after filing out instances under the old class name. In this case, you can type the new name of the class in the dialog and press OK to resume loading. • You might be loading an object whose class you have forgotten to install in your image. If you have a definition of the class available, file it in first and then try loading again. Modified Classes When a change in class definition is detected, the object load map dialog opens (see figure 10-1). This allows you to indicate graphically how filed instance variable values are to be loaded into the new class definition. The name of the class is displayed at the top of the window; if you are loading into a renamed class, you see both the filed name and the new name. Two columns of instance variable names are shown. On the left is a list of the instance variables of the filed instance, with a triangular plug symbol next to each name. On the right is a list of the instance variables now defined for the class, with a socket- shaped symbol next to each name. By default, instance variables with the same name are connected by a line between the plug symbol and the socket symbol. The line indicates that the stored instance variable will provide the value to load into the matching slot in the new instance. If an instance variable in the left column has no connecting line to a socket in the right column, its value will be dropped when the object is loaded. This occurs when the instance variable has been deleted from the class definition since the object was stored. It can also occur as the result of renaming an instance variable. If an instance variable in the right column has no connecting line back to a plug in the left column, its value will be nil when the object is loaded. This occurs when the instance variable has been added to the class definition since the object was stored. It can also occur as the result of renaming an instance variable.

Visual Smalltalk Enterprise Language Reference 229 CHAPTER 10 Object Filer

Figure 10-1: Object Load Map Dialog

You can remedy either situation in one of three ways: • If you have deleted an instance variable, you do not need to take any action. You can load the class, and the value of the deleted variable will be dropped. • If you have renamed an instance variable, you can graphically connect a plug representing an old instance variable name to a socket representing a new instance variable name (see figure 10-2). Connecting plugs and sockets graphically instructs the Object Filer to modify the stored instances accordingly as it loads the objects. • If you have added an instance variable to a class and the value needs to be initialized, you should implement a fileInActivate: method in the class before loading instances of the class as described in the section below entitled Dump Preprocessing and Load Activation. If you are not sure of the correct mapping, cancel the operation until you have been able to investigate the situation further.

230 Visual Smalltalk Enterprise Language Reference Resolving Class Definition Changes

Figure 10-2: Resolving an Object Filer Class Discrepancy

To add a connection: 1 Select a stored variable plug (on the left), by placing the cursor on it and pressing and holding down the left mouse button. Your mouse movements are now tracked until you specify the other side of the connection. 2 Drag the cursor to the other column and release the mouse button over the chosen socket symbol. A new connecting line appears. If you decide not to connect two symbols after all, release the mouse button anywhere on the left half of the load map. To remove a connection, drag the connection away from the plug you wish to disconnect and drop the connection on the desktop. When you are satisfied with the connections displayed in the window, select OK to resume object loading. Pre-specifying Class Definition Changes If you repeatedly load filed objects whose definition has changed, either because the class was renamed or the instance variable layout has changed in the loading image, it is useful to prespecify the information for resolving the missing or modified classes. You can also prespecify the instance variable mapping when the class has a very large number of instance variables. The Object Filer allows you to pre-specify such changes for one or more classes when you load a filed object. The interactive dialogs for renaming a class or defining instance variable connections are suppressed when you have supplied a change specification for a filed class. If a missing or modified class is encountered for which no change specification has been supplied, the usual interactive dialog is displayed to allow you to resolve the class definition change.

Visual Smalltalk Enterprise Language Reference 231 CHAPTER 10 Object Filer

To prespecify class changes, you provide a collection of ObjectChangeMap instances to an Object Filer load operation. An instance of ObjectChangeMap must specify the source class name of the filed object and the destination class name into which the filed instances will be loaded. This allows you to automatically handle renaming a class. If the class name has not changed, the source and destination class names are the same. By default, an instance of ObjectChangeMap specifies that each filed instance variable is loaded into a destination instance variable having the same name, if one exists. You can override this default mapping to specify which filed variable value to load into each destination variable. This allows you to rename instance variables. To create an instance of ObjectChangeMap for a renamed class, write an expression of the form: ObjectChangeMap forClassName: #OldClassName; destinationClassName: #NewClassName. An expression such as this can also be used if you have added or removed instance variables in the renamed class, and you want the default load mapping done by matching instance variable names. To create an instance of ObjectChangeMap for a class to which you have added or removed instance variables, write an expression of the form: ObjectChangeMap forClass: MyChangedClass or ObjectChangeMap forClassName: #MyChangedClass This expression creates a change map with the name of your class as the source and destination class names. The instance variables are loaded using the new class definition, mapping the filed values into the current definition by matching instance variable names. If you have renamed an instance variable, you must specify the connection from the old instance variable name to the new name wherever necessary. You can do this with an expression of the form: (ObjectChangeMap forClass: Foo) put: 'badlyNamedVariable' into: 'newAndBetterName'; yourself.

232 Visual Smalltalk Enterprise Language Reference Resolving Class Definition Changes or: (ObjectChangeMap forClass: Foo) set: 'newAndBetterName' from: 'badlyNamedVariable'; yourself. Any variables in the destination class for which a load connection is not defined will be loaded with the filed value of the same name, or nil if it is a new instance variable. If you wish to drop the filed value of an instance variable, specify this with an expression of the form: (ObjectChangeMap forClass: Foo) put: nil into: 'variableToBeCleared'; yourself. This causes nil to be loaded into the destination variable, even if a value was dumped under that name. If you have added instance variables to a class, consider implementing a fileInActivate: method in the class, if it is necessary to initialize the instance variables that you have added. Please refer to the section entitled Dump Preprocessing and Load Activation for information about this. The following messages allow you to pre-specify class change mappings when loading an object: loadAllFromPathName: aPathName loadMaps: loadMaps This class method returns a collection containing all the objects stored in the file specified by aPathName. The loadMaps argument is a collection of instances of ObjectChangeMap that specify how classes are to be renamed, or how changes in class definitions are to be resolved. loadFrom: aStream loadMaps: loadMaps This class method returns the stored object at the current position on aStream. The loadMaps argument is a collection of instances of ObjectChangeMap that specify how classes are to be renamed, or how changes in class definitions are to be resolved. loadFromPathName: aPathName loadMaps: loadMaps This class method returns the first object stored in the file specified by aPathName. The loadMaps argument is a collection of instances of ObjectChangeMap that specify how classes are to be renamed, or how changes in class definitions are to be resolved.

Visual Smalltalk Enterprise Language Reference 233 CHAPTER 10 Object Filer

loadFrom: aStream loadMaps: loadMaps This instance method returns the object encoded on aStream at the stream’s current position. The loadMaps argument is a collection of instances of ObjectChangeMap that specify how classes are to be renamed, or how changes in class definitions are to be resolved. For example, suppose you are creating a class named Foo that is defined as: Object subclass: #Foo instanceVariableNames: 'this that theOtherThing' classVariableNames: '' poolDictionaries: '' Using the Object Filer, you store several instances of Foo. Sometime later, you decide that the class is badly named and the instance variables aren’t quite right, so you change the class definition to: Object subclass: #BetterFoo instanceVariableNames: 'this theOther somethingNew' classVariableNames: '' poolDictionaries: '' In this new class definition, one instance variable has been dropped, that, another has been renamed, theOtherThing is now simply theOther, and a new instance variable has been defined, somethingNew. Furthermore, the renamed instance variable is in a different position in the object in the new class definition. To load the Foo instances that you previously stored, you can create an ObjectChangeMap to prespecify both the class name change and the instance variable mappings. The following expression loads your old Foo objects into the new BetterFoo class: | fooChangeMap | fooChangeMap := (ObjectChangeMap forClassName: #Foo; destinationClassName: #BetterFoo; set: 'theOther' from: 'theOtherThing'; yourself. ^ObjectFiler loadFromPathName: 'OldFoos.obj' loadMaps: (Array with: fooChangeMap) When you evaluate this expression, the stored Foo objects are automatically loaded as instances of your renamed class BetterFoo. The stored values of the obsolete instance variable

234 Visual Smalltalk Enterprise Language Reference Describing Stored Objects

that are dropped, because you did not specify a destination variable to load them into. The values of the renamed instance variable theOtherThing are loaded into the instance variable theOther, in a new position in the object. The new instance variable somethingNew that you have added to the class is loaded with nil. The values of that are loaded into that, as you would expect, because the name has not changed and you have not overridden the default load mapping that mapped the filed value into the destination variable of the same name. Describing Stored Objects The Object Filer allows you to obtain reports summarizing the classes whose instances are stored in a file, or describing each instance in detail. Summaries You can get a report summarizing the classes whose instances are included in a stored object. For each class, the instance variable definition of the stored object is given, as well as the number of instances of the class that exist in the file. This is useful for analyzing a filed object or determining if any class definitions may require modification before loading the objects described into your image. You can get this class report in any of three ways: • To open a file dialog to specify the filename interactively, execute: ObjectFiler describeClasses • To write the description of the contents of a specified file to another specified file, execute: ObjectFiler describeClassesFromPathName: srcPathName newFile: dstPathName • To write the description of the current position of a stream to another specified stream, execute: ObjectFiler describeClassesFrom: srcStream to: dstStream You can also send the message above to an instance of the Object Filer as well as the class.

Visual Smalltalk Enterprise Language Reference 235 CHAPTER 10 Object Filer

Detailed Reports You can get a detailed report describing all the objects stored in a specified file in any of three ways: • To open a file dialog to specify the filename interactively, execute: ObjectFiler describe • To write the description of the contents of a specified file to another specified file, execute: ObjectFiler describeFromPathName: srcPathName newFile: dstPathName • To write the description of the current position of a stream to another specified stream, execute: ObjectFiler describeFrom: srcStream to: dstStream Customizing the Object Filer The Object Filer allows you to customize its behavior in a number of ways. You can: • Specify that objects defined as instances of a given class must always be stored as instances of another class. • Specify that objects stored as instances of a given class must always be loaded as instances of another class. • Specify that the Object Filer behave in a context-sensitive manner. • Provide your own message-handler for Object Filer messages. Dump Preprocessing and Load Activation Class Object implements dump and load methods that return self, performing no special processing under ordinary circumstances. However, some system objects require preprocessing before they are stored and postprocessing after they are loaded. For example, objects that have pointers or handles to memory (such as instances of Bitmap) must have such handles or pointers set to nil before storing; they also require special processing to restore the handle or pointer to a meaningful value after loading.

236 Visual Smalltalk Enterprise Language Reference Describing Stored Objects

For example, if your image stores objects that refer to a database system, you will simply store the text strings to pass to a server to allow it to connect to the database, instead of the connection objects themselves. Under some circumstances, the Object Filer does the preprocessing for you automatically. If your image includes an open file, the Object Filer stores only a text string specifying the filename, instead of host operating system handles that represent the open file. In that way, when the stored objects are loaded into another image in which that file is not open, you or your colleague can simply reopen the file rather than receiving an error because the file is not open. The Object Filer allows you to specify precisely how you want to transform certain objects, both upon storing to a file and after loading from a file. The dump and load methods are implemented in certain system classes in order to properly save and restore objects that require special processing. The Object Filer sends a message to each object to prepare it for storing and to restore it to a valid state after loading. Dump Preprocessing In order to perform dump preprocessing, implement an instance method called fileOutSurrogate: for the object. An object’s fileOutSurrogate: method is invoked when the object is first encountered during the storage enumeration, before its contents are inspected by the Object Filer. The method returns the object whose contents are to be filed out to represent the receiver. This storage surrogate may be one of the following: • The original object (possibly with changed values in instance variables) • A copy of the original object (that allows changes to instance variables without disturbing the original object) • An instance of a different class suitable for representing the original filed object (such as an OrderedCollection for a SortedCollection) A fileOutSurrogate: method can be used to implement decisions about where to terminate the enumeration of the set of objects reachable from a root object. To do so, return a surrogate object with alternate values for any instance variables that are not to be included in the stored object—for example, nil, or an instance of some placeholder class that can be used to restore a connection to the referenced object.

Visual Smalltalk Enterprise Language Reference 237 CHAPTER 10 Object Filer

Load Postprocessing Activation To perform any postprocessing necessary to restore a loaded object to a useful state, implement an instance method called fileInActivate: for the object. This method must return an object that can be either of the following: • The receiver (possibly with changed values in instance variables) • An instance of a different class, the one that the receiver represented in the stored object An object’s fileInActivate: method is invoked after all objects pointed to by the root object have been loaded, in reverse order from the order in which the objects were stored. In general, this means that an object is activated—modified as specified by the fileInActivate: method—before other objects that refer to it are activated. For example, if you store an object that represents an employee, which refers to another object that represents a payroll account number, the object representing the payroll account number is activated before the object that represents the employee. However, the ordering cannot be guaranteed when circular references exist within the set of stored objects. A fileInActivate: method can also be used to initialize an instance that has been loaded into a class with a different instance variable layout than that with which it was filed. This is useful when the class’s instance variable definitions have changed or when you are using the Object Filer to convert instances to a different class. Reporting Dump and Load Status The argument supplied to both the fileOutSurrogate: and fileInActivate: methods is the instance of ObjectFiler that is performing the dump or load operation. If you wish to notify the user of a nonfatal error that you detect in your storage or load processing, include in your method an expression of the form: anObjectFiler recordWarningMessage: 'description of problem encountered' Your warning message is recorded in the Object Filer message log. When the operation is completed, the Object Filer opens a window containing the messages encountered during the operation.

238 Visual Smalltalk Enterprise Language Reference Describing Stored Objects

You can also record status information with an expression such as: anObjectFiler recordInfoMessage: 'Operation performed successfully.' Finally, you can cancel a dump or load operation because of a fatal error with an expression such as: anObjectFiler recordAbortMessage: 'Fatal error encountered - the operation was canceled.' Attaching Client Context to an Object Filer Operation Two instance methods allow the client of an Object Filer dump or load operation to attach client-specific context information to the operation. This allows applications to implement context- dependent fileOutSurrogate: and fileInActivate: methods. clientContext Return the client context associated with the current dump or load operation. This method allows the context to be accessed in fileOutSurrogate: and fileInActivate: methods, thus allowing context-dependent behavior. clientContext: anObject Hold anObject on behalf of the client. The client context can be accessed in fileOutSurrogate: and fileInActivate: methods to allow context-dependent behavior. To use the client context feature, register your client context object before beginning the dump or load operation. Define a class to represent the context. For example: | aFileStream anObject | aFileStream := File newFile: 'SomeObj.obj'. ObjectFiler new clientContext: MyContext new; dump: anObject on: aFileStream. aFileStream close. In the fileInActivate: and fileOutSurrogate: methods, verify that the client context is available and that it is the correct context. For example: fileInActivate: anObjectFiler | context | context := anObjectFiler clientContext. context isMyContext ifTrue: [ context-dependent activation code here ]. ^self

Visual Smalltalk Enterprise Language Reference 239 CHAPTER 10 Object Filer Providing Your Own Message Handler Ordinarily, an Object Filer opens a text window and displays information or warning messages in that window if any such messages are reported during a dump or load operation. However, you can install your own message handler to present such information differently, or to filter the messages that are displayed. The following instance method allows the client of an Object Filer dump or load operation to control how information and warning messages are presented to the user: clientMessageHandler: aHandler Registers a client message handler. aHandler is a two- argument block or message that is invoked when a problem is encountered during object loading or storing. The first argument is the instance of the Object Filer. The second argument is an association with the following key and value information:

Key Value info A string containing an information message warning A string containing a warning message abort A string containing a fatal error message summary A dictionary containing the message counts by type in the value field of the Association

If messages were encountered during the dump or load operation, the summary notification is sent when the operation is completed. This allows a client to perform summary or termination processing. To install your own message handler, invoke the Object Filer using an instance method. Register your message handler before initiating an object dump or load operation. For example, suppose you have a class named MyDataManager that manages storing and loading objects for your application. You have decided that you want to log any Object Filer messages about loading and storing objects into a file, rather than having them displayed in a window. To do so, implement a message-handling method in MyDataManager. In this example, assume that you have defined an instance variable named warningStream on which to record messages.

240 Visual Smalltalk Enterprise Language Reference Automatic Smalltalk Library Binding

For this example, the method in MyDataManager that stores your objects might look like the following: store: someData fileName: aFileName | myHandler objectStream | myHandler := Message new receiver: self; selector: #messageHandler:message:. objectStream := File newFile: aFileName. ObjectFiler new clientMessageHandler: myHandler; dump: someData on: objectStream. objectStream close. The message-handling method in MyDataManager might look something like: messageHandler: anObjectFiler message: assoc | msg | (assoc key = 'summary') ifFalse: [ "info or warning message" self warningStream nextPutAll: assoc value; cr] ifTrue: [ "summary count of messages" msg := (assoc value at: 'summary') printString, ' messages reported while storing data '. self warningStream nextPutAll: msg, cr. self warningStream close. MessageBox warning: msg, ' (See Messages.log)'. ]. The message above assumes the following method: warningStream

warningStream == nil ifTrue: [warningStream := File newFile: 'Messages.log'.] ^warningStream

Automatic Smalltalk Library Binding When an object is dumped from a Visual Smalltalk image, the information stored in the filed object includes the name of each class that is in a user Smalltalk library (that is, each library not in the base system). When the filed object is reloaded, the Object Filer will attempt to bind that Smalltalk library if the class does not

Visual Smalltalk Enterprise Language Reference 241 CHAPTER 10 Object Filer

already exist in the loading image. If the library cannot be bound or is bound but does not contain the desired class, the missing- class prompt is displayed. If you are dumping instances of a class that currently exists in your image for which you intend to build a Smalltalk library and would like the automatic binding to be done when the filed object is reloaded, you can provide the Object Filer with the intended library name that you want to be used for that class. libraryMappings: anIdentityDictionary Register the Smalltalk library mapping dictionary to use for object dumping. Entries map a class to a string containing the name of the Smalltalk library file to associate with instances of that class stored in the file object. The library association is used during loading to attempt to locate the class, if it is missing. You must invoke the object dump operation with the dump:on: instance method of an Object Filer to use this feature. For example: | sllMappings fileStream | sllMappings := IdentityDictionary new at: Foo put: 'FooBar'; at: Bar put: 'FooBar'; yourself. fileStream := File newFile: 'TestDump.obj'. ObjectFiler new libraryMappings: sllMappings; dump: (Array with: Foo new with: Bar new) on: fileStream. fileStream close.

242 Visual Smalltalk Enterprise Language Reference CHAPTER Workbench Link 11 Protocol Overview This section describes the basic architecture and protocol of the link mechanism in the workbench. Links are created in the workbench to specify the communication between components in the application. Link Basics A link is triggered by an object when an event occurs that the object supports. Each event supported by an object can trigger one or more links. The firing order of the links is specified by sequencing them into the desired order. An event link can in turn trigger either argument links, which collect values for the message arguments, or a result link, which is triggered with the result of the message as its event value. The argument and result links directly triggered by an event link are its immediate dependent links. In the general case, an event link can trigger a network of argument and result links. When an application is being edited, messages can be sent to the PARTS Workbench editor to create and remove links in the application. The createLinkFrom:event:to:message: message is used to create a link and is sent to the part application’s PARTSEditor. createLinkFrom: sourceComponent event: anEvent to: destComponent message: aSelector Create a link which sends the message aSelector to destComponent when sourceComponent triggers the event anEvent. Display the link. Answer the new link. The arguments anEvent and aSelector are symbols and should be prefixed with the # character. For example, this message is used when a part has just been added to an application and automatic links are created to install default behavior. Similarly, the removeLink: message can be sent to a part's editor to remove a link from the application.

Visual Smalltalk Enterprise Language Reference 243 CHAPTER 11 Workbench Link Protocol

removeLink: aLink Removes the link, aLink. Defining Links When creating links, it is usually sufficient to simply define an event link. Default argument links are created if there are event values available to provide message argument values. If more complex behavior for the link must be specified, such as defining argument links to specify the message argument values for the event link, messages can be sent to the link which has just been created to create dependent links. For example, suppose you have created a new part which by default initializes the titles of all window parts in the application to its value. You could do this by implementing the following two methods in your part class: partAddedTo: anApplication " The receiver has just been added to anApplication. Install default links to all window parts in the application. " self partApplication components do: [ :aPart | self createDefaultWindowLink: aPart ]. self partEditor when: #addedPart: send: #createDefaultWindowLink: to: self. createDefaultWindowLink: aPart " Private - create a link which sets the title of aPart to the receiver's value if it is a Window part. " | aLink | aPart isPARTSWindowPart ifFalse: [ ^self ]. aLink := self partEditor createLinkFrom: self partApplication event: #open to: aWindowPart message: #setLabel: . aLink linkArgument: 1 to: self message: #value. Note the use of the editor event addedPart: in the preceding. This event allows you to install the desired default links for any window parts which are added to the application after your part. The firing sequence of links can be modified by reordering the link list of an event. Suppose you have created a part which wants to ensure that its initialization links are always evaluated first

244 Visual Smalltalk Enterprise Language Reference Traversing Links

when the application is launched. You can do this by implementing a method such as the following which could then be called from your partAdded: method: prioritizeInitialization " Private - reorder the initialization links in the application containing the receiver to ensure that links to the receiver are always fired first. " | containingApplication linkList myLinks otherLinks | containingApplication := self partApplication. linkList := containingApplication partLinksForEvent: #open. myLinks := linkList select: [ :aLink | aLink destinationObject == self ]. otherLinks := linkList select: [ :aLink | aLink destinationObject ~~ self ]. containingApplication partSetLinks: myLinks, otherLinks forEvent: #open. Traversing Links The links in an application can be traversed by sending messages to parts to get the event links that the part triggers. The message partLinkTriggers can be sent to any part to obtain the list of events which trigger links from that part. The links triggered by a particular event are obtained by sending the message partLinksForEvent: to any part. Once the list of links is obtained, the link network of argument and result links which are initiated by an event link can be followed by sending messages to the links. You can send the dependentLinks message to a link to get the argument and result links which are directly triggered by the link, or the message withAllDependents to obtain a collection containing all the links in the link network initiated by that link. The messages isEventLink, isArgumentLink and isResultLink can then be sent to the link to determine the type of link. Traversing and editing links can only be done in an editable application. In general, this means when the application is a loaded into a workbench window being edited. Consequently, any methods which you implement which operate on links should either be methods which are only executed in the workbench environment or should contain checks for whether the part is being edited before executing the link editing code. You can

Visual Smalltalk Enterprise Language Reference 245 CHAPTER 11 Workbench Link Protocol

check for edit status of the application using the following expression, which will return true if the part application is being edited: self partIsEditing When an application is executed, the links in the application are installed in the event tables of the parts in the application as messages. Consequently, application execution uses the standard Visual Smalltalk event system. If your part analyzes behavior or dynamically modifies behavior during application execution, use the standard event system services such as when:send:to:, when:send:to:with: and hasActionForEvent: to register and query event handler for your part. Link Message Interface Following is a list of the link message interface, listed by class: Object Messages partDefineLinkForEvent: eventName to: aPart message: messageName Create a link from the receiver, triggered by the event named eventName, which sends the message named messageName to aPart. Answer the new link. partLinksForEvent: eventName Answer a list of the links triggered by eventName from the receiver. The order of links in the list is the firing sequence. partLinkTriggers Answer a list of events which trigger links from the receiver. partSetLinks: anOrderedCollection forEvent: eventName Set the links triggered by eventName from the receiver to anOrderedCollection. PARTSEditor Messages createLinkFrom: sourceComponent event: anEvent to: destComponent message: aSelector Create a link which sends the message aSelector to destComponent when sourceComponent triggers the event anEvent. Display the link. Answer the new link. The arguments anEvent and aSelector are symbols and should be prefixed with the # character.

246 Visual Smalltalk Enterprise Language Reference Link Message Interface

removeLink: aLink Removes the link, aLink. PARTSLink Messages dependentLinks Answer a collection containing any argument and result links directly triggered by the receiver, in their firing order. destinationObject Answer the object to which a message is sent when the receiver is fired. isArgumentLink Answer whether the receiver is an argument link which is fired by another link to collect the value for the triggering link's trigger-th message argument. isEventLink Answer whether the receiver is triggered by an event. isInternalArgumentLink Answer whether the receiver is an argument link which collects its argument value from an input argument of the triggering event. (The selector-th input argument provides the value for the trigger-th message argument of the triggering link.) isResultLink Answer whether the receiver is a result link which is triggered with the result value of another link. isWellDefined Answer whether all the arguments needed to fire this link have a collection mechanism fully defined. linkArgument: argumentIndex to: aPart message: messageName Create and install an argument link in the receiver which collects the argumentIndex-th argument for the message sent by the receiver by sending the message named messageName to aPart. Answer the new argument link. linkArgument: argumentIndex toEventValue: eventValueIndex Create and install an argument link in the receiver which collects the argumentIndex-th argument for the message sent by the receiver from the eventValueIndex-th value of the triggering event. Answer the new argument link.

Visual Smalltalk Enterprise Language Reference 247 CHAPTER 11 Workbench Link Protocol

linkResultTo: aPart message: messageName Create and install a result link from the receiver which sends the message named messageName to aPart. Answer the new result link. messageSelector Answer the message selector sent by the receiver. numberOfEventArguments Answer the number of arguments provided by the triggering event of the receiver. numberOfMessageArguments Answer the number of argument values which must be supplied to fire the receiver properly. removeLink: aLink Remove the argument or result link aLink triggered by the receiver. resultLink Answer the link which is triggered with the result of evaluating the receiver. Answer nil if not defined. resultLink: aLink Set the result link of the receiver to aLink. sourceObject Answer the source object which triggers the receiver. trigger Answer the event which triggers the receiver. withAllDependents Answer a collection containing the receiver and all argument and result links that it triggers.

248 Visual Smalltalk Enterprise Language Reference CHAPTER The Parts Workbench 12 Code Generator Overview The Parts Workbench File/Save As... menu has an option to save the open part as Smalltalk code in file-out format as a .CLS file. There are several reasons to use this option: • to port a part between Windows and OS/2 platforms • to convert a part into Smalltalk code, either to view a code representation of a part or to adapt a part for use in a pure Smalltalk application • to upgrade a part to use the new language syntax • as an alternate storage format for part source In order to save parts in .CLS format, some additional methods must be added to the part class. Parts provided with Visual Smalltalk and with Parts Wrappers are fully enabled for saving in code format. The methods you need to add to parts that you build in Smalltalk are described later in this chapter. For converting several part files in bulk, use the Part Converter utility. This utility is supplied as a part file, PCONVp.PAR. Saving a Part as Smalltalk Code For a workbench user, saving a workbench part as Smalltalk code differs from other save operations only in the selection of the target file type. To save a part as Smalltalk code: 1 Open the part in the workbench 2 Select File / Save as... in the workbench menu to open the file save dialog. 3 Select Smalltalk code (.CLS) as the file format. 4 Select a name and directory for the file, if necessary. 5 Click OK.

Visual Smalltalk Enterprise Language Reference 249 CHAPTER 12 The Parts Workbench Code Generator

Loading a Part from a CLS File A workbench part that has been saved as Smalltalk code is fully portable to Visual Smalltalk on any operating system platform. The component parts must also exist on the target system. To open a part CLS file: 1 Open a workbench. You can either open a new workbench, or use any workbench that you already have open. 2 Select File / Open... in the workbench menu. 3 Select the CLS file containing the part. 4 Click OK. When you open the source file for a part, Visual Smalltalk loads the code, recreates the part by executing the code, displays a fully editable copy of the part, and closes the file. You can then save the part in any other part file format and use it as usual in building your application. Loading a Part CLS file as Smalltalk Code Since a part saved as a CLS file is represented as Smalltalk code, you can install the code and access it using a code browser, as usual for Smalltalk code. Install the CLS file containing the part as usual, using File / Install... in the Transcript or browser menu. The Smalltalk code defining the part is loaded into Visual Smalltalk as a subclass of PARTSApplicationCoordinator. The methods for creating the part are defined as class methods. You can browse the code using either the Class Hierarchy Browser or the Package Browser. Enabling Code Generation for a Class When you choose to save a part application in Smalltalk code format, the code generator sends messages to each object in the part. Based on the information the object returns, the code generator builds a source representation for the part.

250 Visual Smalltalk Enterprise Language Reference Enabling Code Generation for a Class

Each part is responsible for knowing how it should be represented in Smalltalk source code. Methods in the part class provide this information. Similar methods should be added to any class whose instances might be a part or included in a part. A basic implementation is provided in Object, which generates expressions to send new to the class and set the value each instance variable: aClass new partInstVarName: aVariable1 put: aValue; partInstVarName: aVariable2 put: aValue; partInstVarName: aVariable3 put: aValue. This is seldom the desired behavior, and so you must override the default behavior. You specify object creation behavior by implementing either of these messages in the classes for objects in the part: codeGenerationAddAttributeMessagesTo: Used to replace the default value setting messages following the new message. codeGenerationMessageExpressionIn: Used to replace the new message with the correct instantiation message. Adding Attribute Messages The easiest way to support the code generator is to implement codeGenerationAddAttributeMessagesTo: in each class. The code generator sends this message to an object with an instance of CodeGenerationMessageExpression, the code generator’s model of the code to recreate the part. The codeGenerationAddAttributeMessageTo: method in a class adds selectors to correctly set the state of the instance created by sending new to the class. For example, an instance of Directory should be set with a drive and path name, which are stored in instance variables. To properly set up the object, it adds two selectors to the code generator expression model by sending addSelector: messages: codeGenerationAddAttributeMessagesTo: anExpressionModel "Private - add message models to rebuild the receiver to anExpressionModel."

Visual Smalltalk Enterprise Language Reference 251 CHAPTER 12 The Parts Workbench Code Generator

anExpressionModel addSelector: #drive: with: self drive; addSelector: #pathName: with: self pathName The result is generated code that looks like this: Directory new drive: aDrive; pathName: aPathName In most cases this is sufficient, with a code generation message expression as argument. For additional examples, browse implementers of codeGenerationAddAttributeMessagesTo:. The following are a few of the messages available to add selectors. Refer to the Encyclopedia of Classes for complete set. addSelector: aSelector Add aSelector to the receiver’s list of messages. addSelector: aSelector arguments: anArray Add aSelector to the receiver’s list of messages, with arguments in anArray. addSelector: aSelector with: anObject Add aSelector to the receiver’s list of messages, with anObject as argument. addSelector: aSelector with: anObject with: anObject2 Add aSelector to the receiver’s list of messages, with anObject as the first argument and anObject2 as the second argument. Changing the Creation Message For some classes, you may need to exercise more control over the initialization expressions. For instance, sending new to a class is not always the best way to create a new instance. For these classes, implement codeGenerationMessageExpressionIn:. For example, using codeGenerationAddAttributeMessagesTo: for RGBColor would result in code generator code like this: RGBColor new red: 23; green: 45; blue: 124. This is not the best way to create the new instance. Instead, RGBColor implements this method:

252 Visual Smalltalk Enterprise Language Reference Enabling Code Generation for a Class

codeGenerationMessageExpressionIn: aCodeGenerator "Smalltalk code generation - answer a message expression model of the receiver." | answer | answer := aCodeGenerator messageExpressionToReference: self. answer receiverObject: self class; addSelector: #red:green:blue: with: self red with: self green with: self blue. ^answer This causes the more terse instation expression: RGB red: green: blue: Inheriting Code Generation Behavior In many cases you want a class to inherit code generation behavior from its superclass, and so would send: super codeGenerationAddAttributeMessagesTo: aCodeGeneratorExpression before adding any specific attribute messages. However, if a class is a direct subclass of Object, or does not have a superclass that implements this method, you should not inherit behavior. Doing so would add the default generation behavior to the generated code, which is not desirable. Upgrading Generator Support While the Visual Smalltalk 3.0 code generator mechanism is still supported in 3.1, you should update any parts you have created to use the new mechanism. The new code generation behavior enabling methods are easier, and the resulting code is richer and more readable. For information about the old mechanism, refer to the Visual Smalltalk Programmer’s Guide for version 3.0.

Visual Smalltalk Enterprise Language Reference 253

CHAPTER Dynamic Data 13 Exchange (DDE) Overview Dynamic Data Exchange (DDE) is a message protocol for exchanging data between applications. Two applications participating in DDE are engaged in a DDE conversation. A conversation is identified by application and topic name. The application that initiates the conversation is the client application. The application responding to the client is the server application. Data passed between the client and the server is identified by item name. The application name uniquely identifies the server application. A server may recognize several topics and several items within a single topic. A server application may be engaged in a conversation with several clients applications at the same time and with several servers and/or topics at the same time. Visual Smalltalk provides an easy way for applications to conduct DDE conversation with other applications acting as either a server or client. And, it does not matter whether the other applications participating in the DDE conversation are written in Smalltalk or not. Installing DDE Support DDE support is an installable option. To install DDE support, select DDE in the Services Browser and click Install>>. DynamicDataExchange Class DynamicDataExchange class primarily contains the private environment-specific methods to implement the host DDE message protocol. Instead of interfacing with the DynamicDataExchange class, applications should interface with either DDEClient or DDEServer classes. The DDEClient and DDEServer classes use the low level DynamicDataExchange class methods to provide a higher level of service and abstraction.

Visual Smalltalk Enterprise Language Reference 255 CHAPTER 13 Dynamic Data Exchange (DDE) DDEClient Class A DDE conversation is specified by a pair of entities: applicationName and topicName, and a DDE conversation is always associated with a single client and a single server. An instance of the class DDEClient supports one conversation. Therefore, a Smalltalk application creates an instance of the class DDEClient for each conversation it needs to conduct, where it would be acting in the role of a client. To start a DDE conversation as a client, send the following message to the DDEClient class. DDEClient newClient: anObject application: applicationName topic: topicName Object anObject is a Visual Smalltalk object that wishes to be a DDE client. Both applicationName and topicName are strings. anObject is needed to act as a client to receive requests or data from the server. The server that understands applicationName and topicName must already be running. If a server acknowledges the requested application and topic name, a new instance of a DDEClient object is returned. If no server acknowledges the requested application and topic name, then the method answers with a nil and the conversation can not go on. Once a DDE conversation has started, the Smalltalk client object can use the new DDEClient object as a bridge to interact with the server in several ways. Establish Hot Link with an Item on the Server In a hot link, when the data item changes, the server immediately sends the changed data value to the client. Hot links are established by sending the following message to a DDEClient object: hotLinkItem: itemName class: aClass selector: aSelector. itemName is a string that identifies the data, aClass is a Visual Smalltalk class that specifies the expected format of the data, and aSelector is a two-argument selector that is called when the data comes back. In the selector, the first argument contains the item name and the second argument contains the data in the requested class type format. String and Integer class formats are supported. For example, the following message requests Item1 data to be sent as a Smalltalk String to method item:string: in the client object: hotLinkItem: 'Item1' class: String selector: #item:string:

256 Visual Smalltalk Enterprise Language Reference DDEClient Class

This requires that the method item: string: be implemented in the client object class to receive the data from the server. Whenever the data of a hot-linked item changes at the server side, the hot link’s registered selector (in this example, item:string:) is called. Establish a Warm Link with an Item on the Server In a warm data link, the server notifies the client that the value of the data item has changed, but the server does not actually send the data value until the client requests it. Warm links are established by sending the following message to a DDEClient object: warmLinkItem: itemName class: aClass selector: aSelector. itemName is a string that identifies the data, and aClass is a class that specifies the expected format of the data, and aSelector is a one-argument selector that is called when the data is changed at the server side. In the selector, the argument contains the item name of the changed data. String and Integer class formats are supported. For example, the following message requests that method item: in the client object be called when Item1 item at the server side changes: warmLinkItem: 'Item1' class: String selector: #item: This requires that item: method be implemented in the client object class to receive the message whenever the data at the server changes. Whenever the data of a warm-linked item changes at the server side, the warm link’s registered selector (in the previous example, item:) is called to inform that the data has changed. To obtain the actual data, send a requestItem:class: message to the DDEClient object. Request an Item from the Server Instead of a continual update, to obtain the value of an item once, send the following message to a DDEClient object. requestItem: itemName class: aClass itemName is a string that identifies the data, and aClass is a class that specifies the expected format of the data. String and Integer class formats are supported. This method answers an instance of class aClass containing the data supplied by the server; it will not return until the data is available.

Visual Smalltalk Enterprise Language Reference 257 CHAPTER 13 Dynamic Data Exchange (DDE)

In order not to block the client until the data is available, the following method can be used: requestItem: itemName class: aClass selector: aSelector itemName is a string that identifies the data, aClass is a class that specifies the expected format of the data, and aSelector is a two argument selector that is called when the data comes back. In the selector, the first argument contains the item name and the second argument contains the data in the requested class type format. String and Integer class formats are supported. For example, the following message requests Item1 data to be sent as Smalltalk Integer to method item:integer: in the client object: requestItem: 'Item1' class: Integer selector: #item:integer: This requires that item:integer: method be implemented in the client object class to receive the data from the server. When data is sent by the server, the request’s registered selector (in this example, item:integer:) is called. Execute Commands on the Server A command can be executed on the server by sending the following message to a DDEClient object. executeCommand: commandString commandString is a string, the syntax and the semantics of which are defined by the the particular server. Submit an Item to the Server A client may send an item value to the server by sending the following message to a DDEClient object. pokeItem: itemName object: anObject itemName is a string that identifies the data, and anObject is an object that is to be sent to the server. String and Integer instances are supported. Terminate a Hot Link Hot links are terminated by sending the following message to a DDEClient object. terminateHotLinkItem: itemName class: aClass

258 Visual Smalltalk Enterprise Language Reference DDEServer Class

itemName (an item string) and aClass (a Smalltalk class name) identify the hot link. The hot link should be terminated as soon as it is no longer needed. Terminate a Warm Link Warm links are terminated by sending the following message to a DDEClient object. terminateWarmLinkItem: itemName class: aClass itemName (an item string) and aClass (a Smalltalk class name) identify the warm link. The warm link should be terminated as soon as it is no longer needed. Terminate a DDE Conversation A DDE conversation can be terminated by the following message. terminate A DDE conversation should be terminated as soon as the DDEClient object is no longer needed. Upon termination of a DDE conversation, the DDEClient object is no longer valid and all references to it should be removed. When a new connection to a server/topic is needed, a new DDEClient object must be created. DDEServer Class To start a DDE conversation as a server, send the following message to the DDEServer class: DDEServer newServer: anObject application: applicationName topic: topicName anObject is a Smalltalk object requesting to be a DDE Server. Both applicationName and topicName are strings. anObject is needed to act as a server to receive requests or data from the client. A server’s duty is to provide data about a particular item to clients. A DDEServer object recognizes a particular topic of an application. Potentially, a server may need to interface with several clients and needs to recognize which items are hot linked, warm linked or requested. All of this detail is handled by the DDEServer object. All the server needs to do is to export items that it recognizes to the DDEServer object; the rest is handled by the DDEServer

Visual Smalltalk Enterprise Language Reference 259 CHAPTER 13 Dynamic Data Exchange (DDE)

object. Once a DDE conversation has started, the server object can send messages to the DDEServer object in order to interact with the client in several ways. Export an Item An object that the server knows about can be exported for clients to hot link, warm link or request to by sending the following message to a DDEServer object. addExportedItem: itemName object: anObject itemName is a string that identifies the data, while anObject is a Smalltalk object to be exported. The system-defined standard data transfer format is text, and the above method will convert anObject to text before sending it. The receiving client needs to convert this text to the desired format. If the client happens to be implemented in Smalltalk, the received object will be converted to the class that the client requested. Currently, the classes that can be converted to are String and Integer. Update an Exported Item When the value of an exported item has been updated, send the following message to a DDEServer object. Clients that had hot- linked or warm-linked into the item will receive the new value. updateExportedItem: itemName object: anObject itemName is a string that identifies the data, while anObject is an exported Smalltalk object that has been updated. As above, anObject is converted to text before being sent. Remove an Exported Item To remove an exported item, sending the following message to a DDEServer object. removeExportedItem: itemName itemName is a string that identifies the data. Terminate a DDE Conversation A DDE conversation is terminated by sending the following message to a DDEServer object. terminate

260 Visual Smalltalk Enterprise Language Reference Server Object Messages

A DDE conversation should be terminated as soon as the DDEServer object is no longer needed. Upon termination of a DDE conversation, the DDEServer object is no longer valid and all references to it should be removed. When a new server is needed, a new DDEServer object must be created. Server Object Messages There are several methods that the DDEServer object can send to the server object due to client object’s requests. These are described in this section. Dynamically Export an Item When a client asks for a item that has not been exported by the server, the DDEServer object calls the following method in the server object (the object that registered with the DDEServer object) if the method exists. (Implementing this method on the server object is optional. If this method does not exist then DDEServer will not attempt to call it.) ddeExportItem: itemName itemName is a string that identifies the data. At the ddeExportItem: method, if the server know about the requested item, then it should export the item and return true. If the server does not recognize the requested item, then it should return false. Dynamically Change an Item When a client submits an item to the server, the DDEServer object will call the following method in the server object (the object that registered with the DDEServer object) if the method exists. (Implementing this method on the server object is optional. If this method does not exist then DDEServer will not attempt to call it.) ddePokeItem: itemName object: anObject itemName is a string that identifies the data, and anObject is a Smalltalk object submitted by the client. If the server can accept the submitted item, then the ddePokeItem:object: method should return true; otherwise, it should return false.

Visual Smalltalk Enterprise Language Reference 261 CHAPTER 13 Dynamic Data Exchange (DDE)

Execute a Command When a client requests to execute a command on the server, the DDEServer object will call the following method in the server object (the object that registered with the DDEServer object) if the method exists. (Implementing this method on the server object is optional. If this method does not exist then DDEServer will not attempt to call it.) ddeExecuteCommand: commandString commandString is a string. The syntax and the semantics of commandString is defined by the server. At the ddeExecuteCommand: method, if the server can execute the command then it should return true. Otherwise, it should return false. DDE Examples

Sample Client/Server Application Two sample applications are available to illustrate how to build a client/server application using DDE in Visual Smalltalk. The applications are subclasses of ApplicationCoordinator. Install the application by selecting DDE Sample in the Services Browser. Then evaluate the expressions written to the Transcript to open both the client and the server applications. Each application consists of a window with a single textpane and several entry fields. About the Server To start the DDE server, enter a server name and a topic, then select Server / Start server. The name and topic can then be called by any DDE client.

262 Visual Smalltalk Enterprise Language Reference DDE Examples

After the server is started, three linked items are set up: • a hotlinked item, which holds an integer, • a warmlinked item, which holds a string, • a single-request item, which holds a string. To update any of these linked items, select Update Hotlink, Update Warmlink, or Update Single Request from the Server menu. To terminate the server, select Server / Terminate server. The server also responds to various requests from the client: Execute, Poke, Single Request, Single Execute, and Single Poke. These are described below. When the client sends an “Execute” or a “Single Execute” request, it is handled by the ddeExecuteCommand: method. The argument is the command string from the client, which in a real application would be parsed and acted upon. This application merely returns true to simulate the server’s acting on the command string. When the client sends a “Poke” or a “Single Poke” request, it is handled by the ddePokeItem:object: method. The first argument is the name of the poked item, and the second argument contains the poked object. In a real application, this object would be interpreted as a piece of data for the server’s consumption. This application simply returns true to simulate the server’s receiving and acting upon the data.

Visual Smalltalk Enterprise Language Reference 263 CHAPTER 13 Dynamic Data Exchange (DDE)

When the client sends a “Single Request” request, the single request item string is automatically sent by the server. About the Client To start the client, enter the server host name and topic name, and select Client / Call Sample Server in the client window. When the client calls the server, it requests a hotlinked integer, called “Hot.” The method hotItem:integer: simply writes the integer to the textpane. You can request the warmlink item value by selecting Client / Warm data, and the single request item value by selecting Client / Single request. The client can initiate a number of requests to the server. • To send a command to be executed on the server, enter the command in the “Command for execute:” field, then select Client / Execute command. Enter any string. The “command” is echoed by the server in its text pane. • To “poke” a value to the server, enter the value in the Poke data entry field and select Client / Poke. The data as a string will be displayed in the server’s text pane. In a real application, this would be interpreted as a piece of data for the server. To close all connections the client has established, select Client / Terminate. menu item. About the Fitness Monitor The Fitness Monitor is another example of a DDE server application. You can enter various statistics in its entry fields, and start the monitor counting. From the client application, select Client / Call Fitness Monitor to retrieve its current values. Smalltalk Emuator Server The DDE Smalltalk Emulator example is a Smalltalk expression evaluator server. This feature allows any application with DDE capability to evaluate Smalltalk expressions.

264 Visual Smalltalk Enterprise Language Reference DDE Examples

To demonstrate this feature, install DDE Smalltalk Emulator using the Services Browser. Then start Microsoft Word and open the document file in SAMPLES\DDE that matches your version of Word for Windows:

Document File Version and Platform

STSETUP.DOC Word 1.0 on OS/2 STSETUP1.DOC Word 1.0 on Windows STSETUP2.DOC Word 2.0 on Windows STSETUP6.DOC Word 6.0 on Windows STSETP62.DOC Word 6.0a and higher on Windows

Follow the instructions in the document for installing the Word macros and evaluating Smalltalk expressions.

Visual Smalltalk Enterprise Language Reference 265

CHAPTER Multiprocessing 14 Classes Overview Object-oriented computing in Visual Smalltalk involves objects that send messages to each other to perform useful work. Although this suggests parallel computation, it actually is not. An object always waits to receive a response after sending a message. The situation corresponds to that of using a procedural language in which, at any moment, only one procedure is active in a stack of incomplete procedure calls. In Visual Smalltalk, only one method is active in a stack of incomplete message-sends. Visual Smalltalk simulates parallel processing by defining multiple stacks of incomplete message-sends, where each stack is represented by a separate instance of class Process. Because only one processor really exists, the parallelism is simulated; at any time, only a single process is executing. However, many processes can be ready to execute, and Visual Smalltalk switches to a new current process under well-defined conditions. The Visual Smalltalk implementation of multiprocessing is especially suited to discrete event simulation, because it allows each simulated object to carry out its behavior as a separate process, using instances of class Semaphore to synchronize processes. This chapter covers the following topics: •Process Discusses how processes are created and scheduled, and describes the seven levels of process priorities available in Visual Smalltalk. • The User Interface Process Briefly describes the mechanisms behind the user interface process and the debugger. • Semaphore Describes the class Semaphore and gives examples of its use.

Visual Smalltalk Enterprise Language Reference 267 CHAPTER 14 Multiprocessing Classes Process A Smalltalk process is a sequence of message sends and returned results. An instance of class Process describes such a message send/result sequence. A new process is created by sending the message fork to a block, or the message fork: to the global variable Processor. For example: [Transcript show: 'Hello'; cr] fork or: Processor fork: [Transcript show: 'Hello'; cr]. Transcript show: 'Goodbye'; cr This example creates a separate process to execute the code within the block and continues execution of the current process in the code following the block. The result of the second example displayed in the Transcript is: Hello Goodbye Priorities In the example above, both processes operate at the same priority. As the output shows, the new process is initiated before the current process is continued. This occurs because the new process is scheduled first. However, not all processes operate at the same priority. Process priority determines which process will run at any given time. Higher-priority processes preempt lower-priority processes. Visual Smalltalk has seven levels of process priority. Although they are numbered one through seven, your applications are more apt to be portable if you specify priorities in terms of messages to the global variable Processor, as given in the following table:

Table 14-1: Processor Priorities

Level Message to Processor 7 topPriority 6 realTimePriority 5 highPriority 4 userPriority

268 Visual Smalltalk Enterprise Language Reference Process

Level Message to Processor 3lowPriority 2 backgroundPriority 1 idleTaskPriority

Processes can be created at different priorities by sending the message forkAt: to a block or the message fork:at: to Processor. For example: Processor fork: [Processor fork: [Transcript show: ' world! '; cr] at: Processor backgroundPriority. Transcript show: 'Hello '] at: Processor lowPriority This example creates two new processes: one at background priority (two) and the other at low priority (three). Because higher-priority processes are scheduled first, the output on the Transcript is: Hello world! Process States A process exists in one of several states: ready, active, blocked, or dead. • If a process is ready, the system could execute it at any time. • If a process is active, it is the single process that the system is executing now. This process is the value of the global variable CurrentProcess. • If a process is blocked, it has been created, but is waiting on a semaphore and has not been scheduled, or it has experienced an error. • If a process is dead, it will never execute and the garbage collector will reclaim its memory when no reference to it any longer exists in the system. Figure 14-1 shows the state transitions a process can make.

Visual Smalltalk Enterprise Language Reference 269

The User Interface Process

•An active process becomes blocked when the message wait is sent to a semaphore that has no excess signals. •A blocked process becomes ready when it is the first in the waiting queue of a semaphore and the message signal is sent to the semaphore. •The active process becomes dead when it reaches the end of the block that caused process creation as a result of the fork or forkAt: messages. • A process becomes dead if it is sent the message terminate. The class ProcessScheduler is responsible for scheduling when processes are to execute. A single instance of ProcessScheduler is maintained in the global variable Processor. The process scheduler maintains a queue of ready but inactive processes and determines which ready process is the active process. The highest priority ready process is selected as the active process. If more than one process has the highest priority, the process that has been ready the longest is chosen, until that process gives up control or another higher-priority process is created. When a process terminates, it runs any pending clean-up blocks. For details of clean-up blocks, see the section entitled Ensured Execution in chapter 7, Handling Exceptions. The User Interface Process The Visual Smalltalk user interface is driven by a single process that responds to all keyboard and mouse input events for all windows. The user interface process alternates between responding to an input event and waiting for the next input. When it receives no input, other, lower-priority processes can run. The process scheduler always runs a lowest priority idle process when no other process is active. When a process has an error, you can open a debugger on it. The debugger works by examining the execution state of the process. To be useful to a user, it requires the user interface. When an error in the user interface process occurs, therefore, it sends the message error: to the system. The system then creates a separate process for the debugger. The debugger process becomes the user interface process and the process that experienced the error becomes blocked. This allows the process with the error to be debugged with the debugger.

Visual Smalltalk Enterprise Language Reference 271 CHAPTER 14 Multiprocessing Classes

If the process to be debugged is not the user interface process, it becomes blocked, and the user interface process is informed. The current user interface process runs the debugger on it when it has no user input to process. Semaphore A semaphore is a mechanism used to coordinate processes; it can cause one process to give up control to another. This is useful when, for example, one process needs the output of another process in order for it to complete. In that case, one process can announce to a semaphore that it is waiting, and the other process can signal the semaphore when it has produced the required output. The semaphore keeps track of these waits and signals, and passes control from one process to another when it is appropriate. Semaphores are represented in Visual Smalltalk by instances of the class Semaphore. One process waits for the output of another process by sending the message wait to the appropriate semaphore. A process signals that output has been produced by sending the message signal to the semaphore. While a process is waiting on a semaphore, it is blocked. Semaphores can be created by sending the message new to the class. Ordinarily, more than one process can wait on the same semaphore, and more than one process can signal the same semaphore. In such cases, each time a semaphore is signaled, at most one waiting process is made ready. If a semaphore is signaled when no processes are waiting on it, the excess signals are stored. If a process waits on a semaphore that has excess signals, it remains active and one signal is consumed. The following example creates three new processes and uses a semaphore to coordinate between two of them: | aSemaphore | aSemaphore := Semaphore new. Processor fork: [Transcript show: '1 ' ]. Processor fork: [Transcript show: '2 '. aSemaphore wait. Transcript show: '4 ' ] at: Processor lowPriority. Processor fork: [Transcript show: '3 '. aSemaphore signal. Transcript show: '5' ; cr] at: Processor backgroundPriority

272 Visual Smalltalk Enterprise Language Reference Semaphore

The output displayed on the transcript is: 1 2 3 4 5 This output is created as follows: The fork: message creates a process that shows 1. The fork:at:Processor lowPriority message creates a process that shows 2 and then is blocked waiting on the semaphore. The fork:at:Processor backgroundPriority message creates a process that shows 4 and signals the semaphore. This allows the higher-priority process to resume, show 3 and terminate. Then the process at priority 2 resumes, shows 5, and terminates. The initiating process—the user interface process—is blocked, waiting on the semaphore.

Visual Smalltalk Enterprise Language Reference 273

CHAPTER Client/Server 15 Support Overview Visual Smalltalk Enterprise provides extended client/server support for distributed client/server applications with these addition: • GUI-less applications, suitable for running as a server application • TCP/IP (Transmission Control Protocol/Internet Protocol) communications support, for sending messages and arguments between clients and servers • A framework for building applications interacting through sockets Without a GUI, an application interacts with the system console. Visual Smalltalk allows you to launch a Smalltalk application directly from the console command prompt, on operating system platforms that support such a mode of operation. Messages and other interactions take place at the console. Visual Smalltalk Enterprise implements TCP/IP using the Berkeley Socket API. Since the mid 1970s the TCP/IP protocol suite has become the de facto networking protocol standard, and the socket interface to TCP/IP provided in the 4.3 release of Berkeley UNIX has become the de facto API for TCP/IP. Asynchronous Communications In the UNIX world, servers that need to serve multiple clients simply fork off a new process for each client they serve. This makes servers relatively simple to write and makes handling socket calls easy. All socket calls, which are mainly send(), recv(), and the database routines, can simply block until they're finished. This is possible because UNIX processes are pre-emptively time- sliced, with each process running for only a short period before the processor is given over to the next process in line. Smalltalk, on the other hand, depends on cooperation between processes, using semaphores, to allow each other to run. Once a Smalltalk process has control of the image, no other process can

Visual Smalltalk Enterprise Language Reference 275 CHAPTER 15 Client/Server Support

run until control is explicitly passed. Thus, if a Smalltalk process makes a blocking call to the OS, the image essentially halts until that call is completed. Under an OS like Windows, which itself depends on cooperation between Windows processes, once the Smalltalk image has blocked the entire OS is blocked. To allow communications without stopping other processing, Visual Smalltalk implements an asynchronous interface to sockets. In asynchronous mode a socket I/O operation returns control to the caller immediately. When the I/O completes, an interrupt is sent to the caller, and the caller can then finish handling the socket request. In this way, an object performing a socket call can register a handler for the interrupt, perform the call, and return, freeing Visual Smalltalk to continue running. When the socket call has completed the handler is invoked. Console Application Support Smalltalk applications have traditionally made extensive use of a graphical user interface (GUI). This is desirable for client applications, but a server applications does not typically need a GUI, and the additional overhead can be a serious disadvantage. Visual Smalltalk Enterprise provides support for creating an application that does not use the GUI facilities, but interacts directly with the system console. You develop the application in Smalltalk using the standard browsers and tools, but receive input from and send output to a Console object rather than to a window. Starting a GUI-less Development Session The main difference in developing a GUI-less application is the image file you use for developing and executing your application. Instead of developing on V.EXE, you use VNOGUI.EXE. To start a development session using this image, execute: VDEVp VNOGUI.EXE replacing p with ‘w’ for Microsoft Windows platforms or ‘o’ for OS/2. You need to install console support by loading VCON31p.SLL. can add this file to the development image bind file, or select Console in the Service Manager.

276 Visual Smalltalk Enterprise Language Reference Console Application Support

Since your application does not need the PARTS Workbench classes, you should comment out the lines in VDEVp.BND that load the workbench libraries. Insert a semicolon before these lines: ;@PWBRUNp.BND ;@PWBWRKp.BND Your development bind file may include additional files that you similarly want to exclude. Console Support A GUI-less application is one that runs directly from the command prompt, or console. It reads from standard in and writes to standard out and standard error. Support for this mode of operation is provided in class Console. A reference to the console is returned by the expression: Console current If a console is already opened, that is if the application is run from a command prompt, this return that console. If a console is not yet available, such as if the application was launched from an icon or file folder, this expression opens a console window and returns a reference to it. All subsequent interactions with the console, for reading or writing, are sent to the referenced console. The console has a protocol similar to the transcript, and to read and write streams generally. To write a character you send nextPut: to the console, and to write a string you send nextPutAll:. For carriage returns, send cr. To read input from the console, send nextLine, which returns a string. Input can be redirected to and from other devices by using the stdin:, stdout:, and stderror: messages with a file handle as argument. You may also want to set the console window title, which you do by sending the title: message to the console with a string. For additional protocol, browse the hierarchy or refer to the Visual Smalltalk Enterprise Encyclopedia of Classes.

Visual Smalltalk Enterprise Language Reference 277 CHAPTER 15 Client/Server Support

Developing a GUI-less Application There are no particular rules for developing a GUI-less application, and no special frameworks are provided. You can build your application classes anywhere in the class hierarchy. However, since a GUI-less interface is of most interest to a server application running on a TCP/IP connection, you will probably choose to create your application as a subclass of SocketServer, a subclass of SocketCoordinator. Your class will inherit necessary behavior, and you can focus on the specific behavior of your application. As usual, your application will begin by creating an instance of its key class. Since your application may be started from the operating system’s GUI, by clicking an icon, make sure a console window is opened at the beginning of the run. At the same time you can set the window title, using an expression such as: Console current title: 'My GUI-less application'. If the application needs to accept command line parameters, edit the startUpApplication method in SessionModel a remove the default command line handling. You can then access the command line parameters in within the application using: SessionModel current getCommandLine This message returns an array of strings, the first being the command itself, and the remainder being parameters. Input from and output to the console or other devices during the application run is done by reading from and writing to Console current, as described in the previous section. The only remaining concern specifically to your application is to close the console and end the Smalltalk session. These two lines at the end of your exit method will close the application: Console current close. SessionModel current exitSession. The console is closed only if it was opened by the application, at the initial Console current. If the application was started from an already open console window, these lines do not close it.

278 Visual Smalltalk Enterprise Language Reference Console Application Support

Capturing Windows Messages There are times when a GUI-less application still needs to be aware of Windows messages posted to that application. The reason is that not all Windows messages pertain to the graphical concept of a window. Some TCP/IP support depends on windows messages to provide asynchronous communications. In a GUI-less application there is no “event loop” running like there is in the normal Visual Smalltalk session. In order to correctly process windows messages you have to provide your own event loop, but that’s not difficult. You need to catch events before you create any asynchronous socket objects and after you start them running. Before you create any asynchronous socket objects, make sure that the socket event system is initialized. The easiest way to do this is to send cleanUpAllMessages to the Notifier. After all of your asynchronous object have been created and started, you will have to provide a loop to process Windows messages. However, simply placing Notifier cleanUpAllMessages in a loop would cause your application to eat up all available CPU time. Instead, you need to have the process wait until a Windows message is available, then process it. This can be done with UserLibrary class message waitMessage. A simple application would contain code something like this: "Process any pending events" Notifier cleanUpAllMessages. "Start my socket daemon" (FortuneDaemon openOnPort: 5005) start. [true] whileTrue: [UserLibrary waitMessage. Notifier cleanUpAllMessages]. Note that there is no direct way to leave this event loop. This example assumes that the FortuneDaemon provides some way to exit you application.

Visual Smalltalk Enterprise Language Reference 279 CHAPTER 15 Client/Server Support TCP/IP Support InetSocket (a subclass of Socket) is the main class you will use to write TCP/IP code in Visual Smalltalk. The class InetSocket gives you a Berkeley-style socket API: connect, accept, read, write, and close. InetSodket provides access to sockets in the AF_INET address family, such as sockets that use TCP/IP as the communications layer. Two useful subclasses of InetSocket are TCPSocket and UDPSocket, which are used for accessing stream or datagram sockets, respectively. Several additional classes represent the data structures socket programmers typically use: Sockaddr_in, Hostent, Servent, etc. The names of the various socket classes and methods have been designed to reflect the names in the standard Berkeley socket suite. TCP/IP Support Classes TCP/IP support centers around several classes, which are briefly described in the following sections. For complete protocol for each class, refer to the Visual Smalltalk Enterprise Encyclopedia of Classes. The relations between these classes is illustrated in the following figure.

Soc k etC oordinator SocketReadStream SocketError SocketDaemon SocketDaemon SocketWriteStream SocketStructure

Soc k etC h annel Soc k etC onnec tion Soc k et ObjectChannel WinsockDLL InetSoc k et NamedPipe MessageChannel NamedPipeDLL TCPSocket UPDSocket PacketChannel OS2SocketDLL ByteStreamChannel SecureChannel Soc k etNotific ationM anag er

280 Visual Smalltalk Enterprise Language Reference TCP/IP Support

SocketCoordinator SocketCoordinator is a subclass of ApplicationCoordinator. It defines the application view as a socket, which overrides the typical GUI view. Some clients may want to have a GUI as well as a socket view, which can be accomplished by overriding additional methods. SocketDaemon SocketDaemon is the subclass of SocketCoordinator that provides protocol for daemon objects. It assumes that daemons are only interested in two socket events: readyToAccept and connectionClosed. The default buildView:forModel: maps these event to the methods acceptOn: and close, respectively. SocketServer SocketServer is the subclass of SocketCoordinator that provides protocol for server objects. It assumes that servers are only interested in three socket events: readyToRead, readyToWrite, and connectionClosed. The default buildView:forModel: maps these events to the methods readOn:, writeOn:, and close respectively. SocketClient SocketClient is the subclass of SocketCoordinator that provides protocol for client objects. SocketClients initiate a connection to a server, while a server passively waits for one. SocketClients are usually the controlling side of a client/server connection. SocketChannel SocketChannel is an abstract superclass for specific channel classes. When a SocketChannel subclass is instantiated, it is handed a socket or channel upon which it will read and write data. The main purpose of a SocketChannel is to massage the data going in and out through the socket in some higher level manner, perhaps changing the data stream to another form, or mapping some protocol on it. SocketChannels can be considered throwaway objects and may not store state. Several SocketChannels may be open on the same socket. Subclasses of SocketChannels are provided primarily as examples. Application will typically provide their own socket channel classes based on their own protocols. ObjectChannel An ObjectChannel passes objects across the socket using the ObjectFiler.

Visual Smalltalk Enterprise Language Reference 281 CHAPTER 15 Client/Server Support

MessageChannel A MessageChannel encodes messages to be sent to objects existing in the server image. Some handshaking will have already occurred on the socket to establish the link with the remote object. Message parameters are passed using ObjectChannels This is a case where more than one channel must be used on the same socket. EventChannel An EventChannel passes events across the socket in much the same way as a MessageChannel passes messages. There must be an event server on the other end to make sense of the events and pass them on to their intended targets.. Socket Socket provides a Berkeley style socket interface to some communications technology. All subclasses must support at least a portion of this interface: open, close, read, write, bind, listen. The protocol reflects the Berkeley socket API plus higher level protocol hiding details like buffer length and byte ordering. Socket implements a dispatchSelector method to tell the SocketNotifier how to tell it a socket event has occurred. It also implements the eventNameFrom: method to map private event names from socket event handles. SocketReadStream and SocketWriteStream These classes use stream protocol to access the data on a socket. Each instance of these classes buffers the socket data after reading and before writing. Thus, having several streams open on a single socket could cause data synchronization errors. Given that two different read streams fill their buffers at different times it would appear to the other that data was lost. To prevent this, protocol is provided so each instance of Socket can provide a single read stream and a single write stream to those interested in using them. By asking the socket for a stream each user is assured that they will not be “stealing” data from the socket. SocketNotificationManager The class SocketNotificationManager has a single accessed by its class method current. The instance waits for the underlying OS socket layer to send any interesting events. It then sends the event to the interested party. Sockets must register themselves with the SocketNotificationManager if they are interested in receiving such notification.

282 Visual Smalltalk Enterprise Language Reference TCP/IP Support

SocketConnection A socket connection class is the interface to the DLL that provides the OS interface to the communication technology. Its protocol resembles the Berkeley API, and handles whatever processing is necessary to get the data across. SocketError SocketError provides an exception handler for socket errors. It allows socket errors to be signaled based on the Berkeley error codes. SocketError has protocol for mapping from Berkeley codes to system dependent codes. SocketStructure There are several miscellaneous classes to take care of system dependent data structures and the like. Most of these provide Smalltalk classes which represent (and map into) the common C data structures used by the Berkeley socket API such as: hostent and protoent. Structure classes are: Linger, Timeval, Servent, Protoent, Hostent, WSAData, and Sockaddr_in. TCPDaemon A TCPDaemon implements the steps common to daemons which communicate over TCPSockets. It can be created to listen to a port for connection attempts (openOnPort:). When a connection is made it sends serverClass to itself to start a server on the connection. A Finger Client Let’s begin by building a simple client application. Most UNIX systems provide a finger server which gives information on users of that system. The finger server listens to port number 79 for connection attempts, then waits for a user name followed by a carriage return and line feed. It then responds with a variable length string describing that user. The following code is a straightforward implementation of a naive finger client which will display the user information on the Transcript. Assume that teaparty is a UNIX machine and madhatter is a user on that machine. user := madhatter. host := teaparty. socket := TCPSocket new. socket open.

Visual Smalltalk Enterprise Language Reference 283 CHAPTER 15 Client/Server Support

servent := TCPSocket getservbyname: 'finger'. socket connectHost: host port: servent port. finger := String new: user size + 2. finger replaceFrom: 1 to: user size with: user. finger at: user size + 1 put: (Character value: 13). "carriage return" finger at: user size + 2 put: (Character value: 10). "line feed" socket write: finger. fingerInfo := String new: 1024. len := socket read: fingerInfo. Transcript show: (fingerInfo copyFrom: 1 to: len); cr. socket close. We use a TCPSocket because finger is a TCP service. The getservbyname: method will answer the service entry for finger using the TCP protocol. By the way, you could replace that line with: servent := Servent byName: 'finger' proto: 'tcp'. In the next line we connect to the host at the port number for the finger service (servent port). We copy the user id to a new String and append a carriage return and line feed to it (because finger will wait for the CR/LF combination before accepting our input). We then write the user id to the socket and read the result into a new String and print the result on the transcript. We then close the socket. Entering the above code into a workspace and executing it will result in something like the following appearing in the transcript: Login name: madhatter In real life: Tim O'Connor Directory: /usr/teaparty Shell: /bin/ksh On since Oct 4 11:14:53 on ttyp7 from wonderland 12 minutes Idle Time No unread mail Plan: "To See the World in a Grain of Sand and Heaven in a Wildflower, Hold Infinity in the Palm of My Hand and Eternity in an Hour" - William Blake

284 Visual Smalltalk Enterprise Language Reference TCP/IP Support

Socket Streams Two classes provide a Smalltalk style stream interface (not to be confused with streaming sockets) on top of sockets. The class SocketReadStream allows reading on sockets and the class SocketWriteStream allows writing on sockets. We can simplify the finger client by using streams. user := 'madhatter'. host := 'teaparty'. socket := TCPSocket new. socket open. servent := TCPSocket getservbyname: 'finger'. socket connectHost: host port: servent port. socket writeStream nextPutAll: user; cr; flush. socket readStream fill. fingerInfo := socket readStream asString. Transcript show: fingerInfo. socket close. The stream classes allow access to the sockets without explicitly creating and managing buffers in which to hold the data. Several details need to be pointed out. Note that after writing the data to the write stream we sent flush. This ensures that all of the data is written to the socket. SocketWriteStreams buffer the data and flush it automatically when the buffer is full. The size of this buffer can be controlled with the bufferSize: message. Sending flush ensures that the contents of a partial buffer is written to the socket. You may write on the SocketWriteStream in as many separate “chunks” as you wish, just be sure to flush the data when you’re done. The first message sent to the read stream was fill. This will cause the read stream to fill its internal buffer with whatever has been written to the socket. If you access the read stream through messages such as next the buffer will fill automatically. Because asString is defined to return the current contents of the buffer we needed to fill it first. Error Handling Socket errors can be trapped using the standard Visual Smalltalk exception handling mechanism. Class SocketError has been defined to facilitate this. The normal exception handler instance creation protocol has been extended to handle cases where you wish to refer to the socket error by name or error code. For instance, when attempting to connect on a socket which has been

Visual Smalltalk Enterprise Language Reference 285 CHAPTER 15 Client/Server Support

set to non-blocking you may wish to ignore the EWOULDBLOCK or EINPROGRESS errors (because these errors are normally raised in this instance). You would write: [socket connectHost: host port: servent port] on: (SocketError saysName: #EWOULDBLOCK) , (SocketError saysName: #EINPROGRESS) do: [:ex | ex exit: nil]. The same effect would be achieved by writing: [socket connectHost: host port: servent port] on: (SocketError saysCode: 35) , (SocketError saysCode: 36) do: [:ex | ex exit: nil]. Berkeley Data Structures Traditional socket programming depends on a variety of data structures in order to obtain and specify a lot of information. Visual Smalltalk provides classes which map onto these data structures. For convenience the names of these classes are as similar to the names of the original data structures as possible. The Hostent class, for instance, provides the same information as the C hostent data structure. Socket addresses are built and manipulated with the Sockaddr_in class. Socket Database Functions One place where the data structure classes will come into play is with the socket “database” functions. The Berkeley socket suite provides a set of functions whose sole duty is to obtain information about specific hosts or services. Each of these functions returns a specific data structure containing the information. Under Visual Smalltalk each database message will reply with a class which mirrors those data structures. The standard set of database functions is provided as class protocol for the class InetSocket: gethostbyname:, gethostname:, getprotobynumber:, etc. We saw an example of this above when we queried for the port number for the finger server: servent := TCPSocket getservbyname: 'finger'. The variable servent now contains an instance of class Servent which understands the messages name, port, and proto corresponding to the servent structure elements s_name, s_port, and s_proto. As always the names of the various entities have been chosen to reflect the “standard” Berkeley socket suite names.

286 Visual Smalltalk Enterprise Language Reference TCP/IP Support

Instances of these classes can also be created with specific information. To create a socket address, for instance, you would create an instance of Sockaddr_in: Sockaddr_in hostname: 'jabberwocky' port: 24 Asynchronous Sockets The finger client above was described as naive. Not only did it not contain any error handling but it ran using blocking socket calls. The Asynchronous Communications section near the beginning of this chapter discussed the problems with blocking I/O. Every time the naive finger client makes a socket access all Smalltalk processes come to a halt. If the finger server were to never respond to the request then Smalltalk would never get control back. This is obviously a highly undesirable situation in most cases. Since finger typically has fast turnaround it’s not really a problem in this case. Socket Socket provides a Berkeley style socket interface to some communications technology. All subclasses must support at least a portion of this interface: open, close, read, write, bind, listen. The protocol reflects the Berkeley socket API plus higher level protocol hiding details like buffer length and byte ordering. Socket provides an asynchronous interface based on six events: readyToRead Data has appeared on the socket. readyToWrite The socket is ready to receive data. This event is only triggered when the socket is first opened or when some error condition preventing writing has been cleared. In general a socket can be assumed to be in this state. outOfBandData Out Of Band (also known as urgent) data has appeared on the socket and the application should read it. readyToAccept The socket has been listening for connection attempts and one has arrived. connectionCompleted A previously issued connection request has been completed.

Visual Smalltalk Enterprise Language Reference 287 CHAPTER 15 Client/Server Support

connectionClosed The other end of the socket has closed the connection. These events are used in conjunction with SocketCoordinator and its subclasses to build asynchronous socket applications. Writing Asynchronous Applications In traditional client/server applications there are three roles which an application can play. The client is the application which the user typically runs. It takes user input and turns it into requests which it sends on to a server. The client then takes the response from the server and presents it back to the user. The server is typically running on a separate machine and expects to serve many clients. It may be the database behind national car rental outlets, or airline reservation systems. It may simply be an accounting system running in small office. Whatever its function the server typically runs in two phases which we call the daemon and the server. The daemon (a term borrowed from UNIX) is the role played by the server when it sits there waiting for clients to connect to it and request data. Upon a connection attempt the daemon typically spawns a new process to handle requests from that client then goes back to awaiting further connection attempts. The new process is what we call the server. It will handle all the requests from the client until the client disconnects. The server process then closes its socket and is used no more. The asynchronous socket application suite in Visual Smalltalk is built around these three roles: Daemon, Server, and Client. Asynchronous socket applications are written using three subclasses of SocketCoordinator which is itself an ApplicationCoordinator subclass. The subclasses are SocketDaemon, SocketServer, and SocketClient. They interact with each other and the underlying socket layer through the events discussed in the previous section. A Client In this section we will build a simple asynchronous client. About the simplest client I can think of uses the time of day service supported on most UNIX systems. Upon receiving a connection the time of day server responds with the current date and time in an ASCII string. Building a client for this service takes two methods. Our DaytimeClient will be a subclass of SocketClient. On the class side we will provide a method to create a client:

288 Visual Smalltalk Enterprise Language Reference Writing Asynchronous Applications

openOnHostname: hostname "Get the port number of the time of day service and open on it" | service | service := self socketClass getservbyname: 'daytime'. ^self openOnAddress: (self socketClass addressClass hostname: hostname port: service port) SocketCoodinator provides a socketClass class method to determine what kind of socket, streaming or datagram, you’re using. The default is TCPSocket because in most cases that’s what you’ll be using. The first line retrieves information about the time of day service (which is called daytime). We next construct an address composed of the hostname and service port number and use it to create an instance of DaytimeClient. The construct self socketClass addressClass in this case is equivalent to Sockaddr_in. On the instance side you need to provide a connectOn: method which well be sent when the connectionAccepted event is triggered: connectedOn: aSocket "A TCP daytime server sends the data upon connect, just read it" | time | time := String new: 32. aSocket read: time. Transcript show: 'At the tone the time will be '; show: time trimNullTerminator; cr. Terminal bell. self close As mentioned above the time of day service responds upon connection. So the first thing that needs to be done is to read that data. We know that it will return an answer which is 32 bytes long. The current date and time is printed to the Transcript window and the bell is rung to simulate the old-fashion time of day phone number. The socket is then closed. We can close it at this point because the time of day service only responds on connection then closes its side of the socket. There is no reason to leave this client active. A side effect of closing the socket is that the readyToWrite event which always follows a

Visual Smalltalk Enterprise Language Reference 289 CHAPTER 15 Client/Server Support

connectionAccepted is lost because there is no longer an object around to catch it. A more elegant way to ignore unwanted events is shown in a later section. Now to start a DaytimeClient. Open a Workspace and enter: dt := DaytimeClient openOnHostname: 'bingo'. dt start. Select and evaluate these two lines and you should see the time of day printed on the Transcript. Note that you can also run this example synchronously by starting it with the startSynchronous method. The socket examples contain a datagram version of this client (DaytimeClientUDP) which demonstrates how you can create UDP clients. Your Fortune Told Here Now let’s try a full client/server application, both sides of which run on Visual Smalltalk. We will build a fortune server. The protocol is simple. The server will await client connections (SocketDaemon) on port 3062. When a client (SocketClient) connects, a new server (SocketServer) will be instantiated to handle it. Whenever the client sends the string “fortune” the server will respond with a fortune. When the client sends the string “quit” the server will close its socket and so will the client. Any other input is silently ignored. The Fortune Daemon Let’s start with the FortuneDaemon. We will subclass from TCPDaemon, a SocketDaemon subclass which handles most of the steps necessary for building a daemon. In fact in order to create a FortuneDaemon we need only provide two instance methods: serverClass ^FortuneServer defaultPort ^3062 TCPDaemon handles the rest. Actually we don’t even need to do this much work. Evaluating the following expression in a workspace would start a daemon which would handle connection requests for a FortuneServer just fine:

290 Visual Smalltalk Enterprise Language Reference Writing Asynchronous Applications

(TCPDaemon openOnPort: 3062 serverClass: FortuneServer) start As you can see daemons are rather simple beasts. Let’s take a look at some of the inherited behavior to see what’s really going on. Taking a look at SocketDaemon class>>buildView:forModel: we see: buildView: aSocket forModel: aCoordinator

aSocket when: #connectionClosed send: #close to: aCoordinator; when: #readyToAccept send: #acceptOn: to: aCoordinator with: aSocket This specifies what should happen when certain events are triggered. Event triggering takes place by cooperation between the underlying operating system, the SocketNotificationManager and instances of class Socket. You can check out the code for details if you wish. The SocketServer and SocketClient classes contain similar code specifying the events they are interested in. To process connection requests (signaled by the readyToAccept event) TCPDaemon needs an acceptOn: method: acceptOn: aSocket | descriptor | descriptor := aSocket accept: nil. (self serverClass openOnDescriptor: descriptor) start The socket must first issue the accept: to finish the connection request. An instance of the appropriate server class is then created and sent the start method. The Fortune Server The FortuneServer will be a subclass of SocketServer. A SocketServer knows how to handle three events: connectionClosed, readyToRead, and readyToWrite. Of these three we need only provide a handler for the readyToRead case. The default handler for connectionClosed will cause the socket to be closed, which is exactly what we want. We will configure the FortuneServer to ignore readyToWrite messages (and simply assume the socket is always in a writable state). Our readyToRead handler will process requests for fortunes. The default name for the readyToRead handler is readOn:, which we will provide.

Visual Smalltalk Enterprise Language Reference 291 CHAPTER 15 Client/Server Support

First create a class FortuneServer. For convenience assign the CharacterConstants pool to it. FortuneServer will inherit all the class behavior it needs. We will provide it with three instance methods. As stated above we want the server to ignore readyToWrite events. For this simple example we can safely ignore them. In general, however, you should provide a writeOn: method and track these events. If an error is returned from a write operation the readyToWrite event will notify you that the socket is again writable. This time we will override the start: method and tell the socket to ignore write events: start: aSocket

super start: aSocket. aSocket ignoreExternalEvent: #readyToWrite This method is executed in response to sending start to an instance of a SocketServer. The first thing we need do is pass aSocket on up to the superclass so it can set up the event handling for us. Then we tell aSocket to ignore write events. When the readyToRead event is triggered (by presence of data on the socket) the readOn: method will be executed to handle it: readOn: socket | command | command := socket read. (command size >= 4 and: [(command copyFrom: 1 to: 4) = 'quit']) ifTrue: [^self close]. (command size >=7 and: [(command copyFrom:1 to: 7) = 'fortune']) ifTrue: [^socket write: self nextFortune] The first thing we do here is read the data from the socket. Then we check to see if it’s a quit command or a request for a fortune. Checking the substring is a simple way to ignore any line terminators the client may have added. If a request for a fortune has come through we generate a fortune and write it onto the socket. The nextFortune method is completely independent of the socket suite. Here’s a rather simple one: nextFortune "Send an appropriate saying from the I Ching" ^'Heaven and Earth are in harmony. The high and low

292 Visual Smalltalk Enterprise Language Reference Writing Asynchronous Applications

are united.' , Cr asString , Lf asString The Fortune Client The FortuneClient need only write a command to the server then wait for the response. To make things a bit more interesting let’s write a client which will ask for four fortunes then send quit. Create a class FortuneClient as a subclass of SocketClient and give it one instance variable named fortuneCount. Like the server the client will inherit all the class behavior it needs and we need only provide some instance methods. When a client connects to a server it will receive two events: connectionCompleted and readyToWrite. In a simple client like ours we could use the write event as a signal that the connection has been completed and things are ready to roll. The inherited connectedOn: method does nothing for an asynchronous client like ours so there is no need to override it or to ignore it. Our writeOn: method simply needs to ask for a fortune: writeOn: aSocket self getNextFortune: aSocket Next we need to supply a readOn: method to handle readyToRead events. We expect one such event each time we ask for a fortune: readOn: aSocket | fortune | fortune := aSocket read. Transcript show: self class printString , ' read #' , fortuneCount printString , ': ' , fortune trimNullTerminator;cr. self getNextFortune: aSocket First we read the fortune from the socket then display it on the transcript. Then we ask for another fortune. As you can see from above the getNextFortune: method does all of the real work. Here it is:

Visual Smalltalk Enterprise Language Reference 293 CHAPTER 15 Client/Server Support

getNextFortune: aSocket fortuneCount isNil ifTrue: [fortuneCount := 4]. fortuneCount <= 0 ifTrue: [aSocket write: 'quit'. self close] ifFalse: [fortuneCount := fortuneCount - 1. aSocket write: 'fortune'] This is simply a loop which will continue to ask for a fortune until the loop count reaches zero. When the loop count does reach zero the quit command is sent to the server and we close our socket. If this were a more complicated client the decision as to what to send the server would be a combination of user input and response from the server. Channels All of the above examples had at least one thing in common: the data written to and read from the pipe was simple, unformatted text. In most real-world cases the data sent across the socket will not be so simple. You may have an object representing a database query, for example, or a set of deposits and withdrawals to make to a set of bank accounts. Whatever the case your data will probably have some form and you will have to place it on the socket following some specific protocol. This section introduces the concept of a socket channel which you may find to be of some aid. A channel is simply an object which reads and writes formatted data from and to either a Socket or SocketChannel instance. The abstract class SocketChannel captures the basic behavior of a channel and provides three operations: write, read, and process. When an object is written on the socket through a channel that object gets “flattened out,” it gets converted into a stream of bytes suitable for writing on a socket. Reading through a channel results in an object which is a Smalltalk representation of the “flat” data taken from the socket. Processing through a channel reads the data and performs additional processing to it. Examples of reading and writing are presented below. You can see the MessageChannel class for an example of processing. The MessageChannel and all of the examples presented below can be found in VSCK2nnp.SLL.

294 Visual Smalltalk Enterprise Language Reference Writing Asynchronous Applications

A very simple example of data you may wish to send down a socket is boolean data. A BooleanChannel could be implemented as a subclass of SocketChannel with the following two instance methods: write: aBoolean "Write to the socket as either 0 (false) or 1 (true)"

aBoolean ifTrue: [self socket writeStream nextPut: (1 asCharacter)] ifFalse: [self socket writeStream nextPut: (0 asCharacter)] read "Read from the socket as either 0 (false) or 1 (true)" | value | value := self socket readStream next asInteger. value = 0 ifTrue: [^false] ifFalse: [^true] Look at what’s happening here. We can write a boolean to the channel and it will convert that boolean to either a 1 or a 0 for true or false respectively. When the data is read through a BooleanChannel it comes out as either true or false. Here’s an example of how such a channel might be used (assume aSocket is a valid socket): (BooleanChannel on: aSocket) write: (3 < 4). trueOrFalse := (BooleanChannel on: aSocket) read. Because the channels are converting from Smalltalk object to flat bytes you can write your application without worrying about the conversion yourself. Once you write the channel, that is. Channels are intended to be inexpensive to instantiate. In most cases you can use them just you saw above. Let’s look at a channel which will handle small (16 bit) positive integers. We’ll call it SmallPositiveIntegerChannel. Here’s the behavior:

Visual Smalltalk Enterprise Language Reference 295 CHAPTER 15 Client/Server Support

read "Read the next two bytes from the socket and answer them as a SmallInteger" | hibyte lobyte | hibyte := self socket readStream next asInteger. lobyte := self socket readStream next asInteger. ^(hibyte bitShift: 8) + lobyte write: aSmallInteger "Write to the socket. should be positive and no larger than two bytes in value. Silently ignore any magnitude errors" | hibyte lobyte | hibyte := (aSmallInteger bitShift: -8) bitAnd: 16rFF. lobyte := aSmallInteger bitAnd: 16rFF. self socket writeStream nextPut: hibyte asCharacter. self socket writeStream nextPut: lobyte asCharacter Next we might have a StringChannel which handles null- terminated strings: read "Read bytes from the socket up to and including the next null. Throw away the null and answer a String from the rest" ^(self socket readStream upTo: (0 asCharacter)) asString write: aString "Write to the socket then append a null character" self socket writeStream nextPutAll: aString. self socket writeStream nextPut: (0 asCharacter) So far all of the data we’ve written above has still been flat to start with. Let’s look at what it might take to write an ArrayChannel. In order to be flexible we would like the ArrayChannel to be able to handle sets of different types of data. And we would like to use channels to read and write those different types. We can instantiate channels using the on:with: method. When a channel is created this way the new instance is sent the message initialState: and handed the second argument of on:with:. We then use this argument to set the element type of the ArrayChannel. Let’s see how this works: initialState: anObject "The argument is the channel which will encode our elements" self elementChannel: anObject

296 Visual Smalltalk Enterprise Language Reference Writing Asynchronous Applications

elementChannel: anObject "Set the object will encode/decode our elements" elementChannel := anObject

elementChannel "Answer the object will encode/decode our elements" ^elementChannel So evaluating ArrayChannel on: aSocket with: (StringChannel on: aSocket) creates an ArrayChannel which will use a StringChannel on the same socket to encode and decode its elements. When writing an array to the socket we can first encode the number of elements in the array. This will make it easier to get them out on the other side: write: anArray "Write to the socket using our elementChannel" | numElements | numElements := anArray size. (SmallPositiveIntegerChannel on: self socket) write: numElements. anArray do: [:e | (self elementChannel) write: e] Note how we can make use of other channels to place data on the socket. This is how we can structure the flat data in more interesting ways. Reading the data requires us to construct a new Array and fill it: read "Get the number of elements then have our elementChannel read each" | numElements newArray | numElements := (SmallPositiveIntegerChannel on: self socket) read. newArray := Array new: numElements. 1 to: numElements do: [:i | newArray at: i put: (self elementChannel) read]. ^newArray Now that we have an ArrayChannel creating something like an ArrayOfStringsChannel channel is trivial:

Visual Smalltalk Enterprise Language Reference 297 CHAPTER 15 Client/Server Support

read ^(ArrayChannel on: self socket with: (StringChannel on: self socket)) read write: anArray (ArrayChannel on: self socket with: (StringChannel on: self socket)) write: anArray Sockets and Parts This section presents a method for merging sockets with the Parts workbench to create parts which will let other parts access network services via TCP/IP. The following discussion assume you are familiar with using Parts and constructing parts from Smalltalk. All three of the classes discussed in this section can be found in the VSCKnnp.SLL file. First we will walk through building a couple of useful TCP/IP parts then we will use those parts to construct a time of day application. A Socket Address Part For our first example let’s take a look at how to build a part which will construct a socket address (a Sockaddr_in) when handed a host name and a port number from another part. First create a class named SocketAddressPart as a subclass of PARTSNonvisualPart. This class will inherit all the class behavior it needs and we need only write two instance methods. The partMessages method is used to specify the messages that a part will understand. We will only have one part message: partMessages ^PARTSInterfaceList new items: #(#fromHostname:port:) defaultItem: #fromHostname:port: And the implementation of the above message: fromHostname: hostname port: port "Answer a Sockaddr_in built from the arguments" ^Sockaddr_in hostname: hostname port: port

298 Visual Smalltalk Enterprise Language Reference Writing Asynchronous Applications

A Socket Client Part Building a socket client part will be a bit more involved then building a socket address part was. We will need to create two classes: one class to interface with PARTS and another to interface with sockets. The part will delegate socket requests to the socket client. Let’s start by discussing the socket client part. We would like the user of this part to be able to create links to it which will cause socket requests to take place. In particular we would like to specify an address for the client, we need to start it running, we need to read and write to it, and we need to close it down. The events this part will trigger will be related to the state of the socket transaction. That is, the part will trigger events when the socket has completed connecting to a server, when there is data to be read, and when it has been placed into a writable state. Create a class called SocketClientPart as a subclass of PARTSNonvisualPart and give it one instance variable: socketClient. This variable will contain an instance of the SocketClient subclass to which the part will delegate socket requests. We don’t need to add any class behavior. Add a method named partEvents to specify the events this part will trigger: partEvents ^PARTSInterfaceList new items: #(#connectionCompleted #readyToRead #readyToWrite) defaultItem: #connectionCompleted Also add a method names partMessages to indicate the messages this part can receive: partMessages ^PARTSInterfaceList new items: #(#openOnAddress: #start #startSynchronous #read #readObject #readInto: #writeFrom: #writeObject: #close) defaultItem: #openOnAddress: Now you need to add a method for each of the messages in the list above. You can browse the example to see the complete implementation but let’s take a look at two of the methods here.

Visual Smalltalk Enterprise Language Reference 299 CHAPTER 15 Client/Server Support

The openOnAddress: method will take as input a result link from the above SocketAddressPart. It will then create a socket client and cache it in the socketClient instance variable: openOnAddress: anAddress "Create a socket client on the address. Tell it who we are" self socketClient: (SocketPartClient openOnAddress: anAddress). self socketClient clientPart: self The read method will return the data read from the socket: read "Read from the socket" ^self socketClient read Notice how the part messages are simply delegated to the socket client for actual processing. Now let’s take a look at the socket client. Create a class called SocketPartClient as a subclass of SocketClient and give it two instance variables: clientPart and socket. The clientPart variable will hold a reference to the SocketClientPart which uses this client. The socket variable will hold a reference to the socket which this client uses. SocketPartClient inherits all the class behavior it needs. We need to add a start: method to catch the socket descriptor when the client is started: start: aSocket "We're starting up. Cache the socket for later use" self socket: aSocket. super start: aSocket This method caches the socket descriptor into the socket variable then let’s the superclass continue the startup processing. Now we need a way to pass the socket events on to the SocketClientPart. Here’s an example using the readyToRead event: readOn: aSocket "Inform the part that there is data to be read" self clientPart triggerEvent: #readyToRead Presumably once the part sends the readyToRead event on to another part, that second part will send some read message on to it. Then the part will delegate the read message to the client. So we need a method like:

300 Visual Smalltalk Enterprise Language Reference Writing Asynchronous Applications

read "Read whatever's on the socket" ^self socket read Now that we have some socket parts at our disposal we can put them together with some other parts and build a simple time of day application. We will present the user with a window that contains a text area and one button. When the button is pushed the time and date will be displayed in the text area. Here’s what it looks like:

There are a few important things to note in this diagram. First, when the “What time is it?” button is pushed two messages are sent to the SocketClientPart. These must be sequenced so that the openOnAddress: message is sent before the start message is. Also note that the readyToRead event from the SocketClientPart causes the static text part to send a read message back to the SocketClientPart.

Visual Smalltalk Enterprise Language Reference 301 CHAPTER 15 Client/Server Support VisualWorks Compatibility Suite The Cincom VisualWorks product also provides TCP/IP support through sockets. For historical reasons that implementation differs quite substantially from the socket implementation in Visual Smalltalk. This section discusses a compatibility suite which has been provided to ease porting VisualWorks socket-based code into the Visual Smalltalk environment. This compatibility suite can be installed from the VSKVWnn.SLL. The socket support in the VSOCKnnp.SLL needs to be installed prior to installing the compatibility suite. The VisualWorks socket API centers around two classes: SocketAccessor and IPSocketAddress. The VisualWorks socket suite is heavily dependent on processes to do its work. The process model between VisualWorks and Visual Smalltalk differs significantly enough that one warning needs be made:

WARNING: In Visual Smalltalk you must never send a socket message in the User Interface process. Doing so will lock the image into a wait state from which it will never emerge. Always wrap your socket code in a fork block.

The compatibility suite does not provide a full set of the classes VisualWorks socket programmers have become familiar with. In particular class ExternalStream has not been brought over. Read and write streams must be obtained using the SocketAccessor readStream and writeStream protocol. The SocketAccessor protocol has been expanded to include additional messages which the VisualWorks socket programmer uses. Browse the class to see which ones are there. The full set of SocketAccessor examples has been modified to run under Visual Smalltalk. You should take a look at them. What follows is a copy of the on-line SocketAccessor documentation. It describes how to implement a client and server and how to use datagram sockets. It has be slightly rewritten to reflect the programming style needed for compatibility between the to environments.

302 Visual Smalltalk Enterprise Language Reference VisualWorks Compatibility Suite

How To Implement A Client First you need to create the socket and connect it to the server. Let’s assume you know the host name, servicehost, and you know the port number is 175. In that case: skt := SocketAccessor newTCPclientToHost: 'servicehost' port: 175. At this point, the SocketAccessor can be read and written to just like a VisualWorks DiskFileAccessor (for example, you can use readInto:starting... and writeFrom:starting... and readWait and writeWait, etc.). For streaming, you can ask the socket for a stream: readStream := skt readStream. writeStream := skt writeStream. When you’re done communicating with the service, just: skt close. finishes the job. Note the two differences between this implementation and VisualWorks: • Getting access to the socket streams • Closing the stream does not close the socket. How To Implement A Server First, you create a socket and bind it to an address. A more complicated issue is what port number you should assign your service. This issue is discussed in the documentation for class IPSocketAddress Ñ for this example, we’ll assume you’ve already arranged for your service to be at port 175. So: skt := SocketAccessornewTCPserverAtPort: 175. ...now you’ve published a socket for your host at port 175, but you need to accept the connections which will be arriving. First, you construct a connection queue of some maximum length (5 is the longest queue most implementations will allow). Let’s say that you’re only willing to handle two clients at a time: skt listenFor: 2. ...now you can accept arriving connections: newskt := skt accept.

Visual Smalltalk Enterprise Language Reference 303 CHAPTER 15 Client/Server Support

...newskt is a new SocketAccessor of an equivalent domain, type and protocol to the original socket. The port number is an arbitrary one assigned by the system. If you wish, you can send getPeer to the newskt first, to validate that your client is originating on a system you are willing to provide services to (if not, you should send close to newskt and start over). Note that this is a blocking accept and will freeze the image until a connection is made. See the method acceptNonBlock and the examples for information on performing a non-blocking accept. At this point you probably want to fork off a process to provide the service, while the original process waits for the next connection with accept. The forked process which actually provides the service will have newskt, a SocketAccessor which can be read and written to just like a VisualWorks DiskFileAccessor (e.g. you can use readInto:starting... and writeFrom:starting... and readWait and writeWait, etc). When you’re done providing the service to a given client, your forked process should just send: newskt close. and terminate itself. When you are no longer willing to accept new connections from clients you just send: skt close Streams can be used on newskt in the same fashion as for client sockets. How To Use Datagram Sockets Connectionless sockets (using datagram sockets) are quite different from connection-oriented sockets. Typically, each transaction is of a known length, and each transaction may be associated with a different peer. First, you construct a socket of the appropriate type: skt := SocketAccessor family: (SocketAddress domainCodeFromName: #afInet) type: (SocketAccessor sockDgram) protocol: (SocketAccessor pfUnspec). ...and then one side would bind to an address: mySa := IPSocketAddress hostName: 'foo' port: 1000. skt bindTo: mySa.

304 Visual Smalltalk Enterprise Language Reference VisualWorks Compatibility Suite

...and perhaps set-up to home to a particular peer: hisSa := IPSocketAddress hostName: 'bar' port: 1000. skt connectTo: hisSa. ...the peer would swap the addresses but execute similar code. At this point, both sides could use their sockets for normal reading and writing, if the transaction sizes were known in advance. If the application were more client/server style, the server would forego the connectTo: (because the client is not known in advance). The client would skip the bindTo:, and let the system assign the socket address. The server would communicate to client(s) by reading with receiveFrom:buffer..., and using the socket address returned, reply to a given client using sendTo:buffer:... The clients could use normal read/write protocol.

Visual Smalltalk Enterprise Language Reference 305

CHAPTER 16 System Classes Overview This section describes a number of classes that are fundamental to the way Visual Smalltalk works. No attempt has been made to explain the actual operation of the Visual Smalltalk system, but some of the classes described here are useful in certain situations in which the state of the system need to be monitored, or a somewhat lower level of control of the environment is required. The section ends with descriptions of object finalization and weak registries. These features involve some additional classes and new methods added to existing classes The classes and topics described here are: • NotificationManager Dispatches events to the operating system. • SystemDictionary Maintains all of the names of the classes, global variables, and pool dictionaries in the system. • ClassReader Is used to file-in and file-out classes. • CompiledMethod Maintains the interpreted code for a Smalltalk method. • Message Defines the basic data structure for messages. • Behavior Defines the common protocol for classes and metaclasses. • EventManager Defines the mechanisms for event handling. • SessionModel Controls many essential system processes, such as startup and shutdown processing for the Visual Smalltalk image. • ServiceRegistry Records services that are available in the system, normally as a result of installing a Smalltalk library.

Visual Smalltalk Enterprise Language Reference 307 CHAPTER 16 System Classes

• ClipboardManager Manages the interface to the operating system clipboard. • Object Finalization Methods, classes and explanations of finalization in Visual Smalltalk. • Weak Pointers Describes weak pointer classes and methods. NotificationManager Notifier, the single instance of NotificationManager, dispatches system event messages from the operating system to Visual Smalltalk. It keeps a collection of all open windows, translates system event messages to Visual Smalltalk messages, and sends the appropriate selector to the window object that matches the WindowHandle in the message. NotificationManager provides the following instance methods: cleanUpWindows Remove the windows that are no longer valid in the host system from the receiver. setPeekCount: anInteger (Windows only) Asks the virtual machine to determine if there is an interrupt request after every anInteger number of message-sends. anInteger must be a SmallInteger. The default is 4096. windows Answers the collection of open windows. yield (Windows only) Yields control to other applications. NotificationManager uses the instance variable windows to keep track of windows objects. This instance variable is a Dictionary containing all open windows that can receive system event messages. The keys are integers representing window handles, and the values are Window objects.

308 Visual Smalltalk Enterprise Language Reference SystemDictionary

SystemDictionary The SystemDictionary class has only a single instance, the global variable Smalltalk. The SystemDictionary contains all of the names known globally within Visual Smalltalk, and defines methods for certain system functions. For example, the following expression forces the garbage collector to perform a compact operation on object memory and computes the number of bytes of available memory in your system: Smalltalk unusedMemory The SystemDictionary contains all of the names of the classes, global variables, and pool dictionaries in the system. As you define classes, global variables, and pool dictionaries, their names are added to the SystemDictionary. For classes in the dictionary, the key is the class name and the value is the class itself. For global variables in the dictionary, the key is the variable name, and the value is the object it represents. If the variable has been defined but not initialized, its value is nil. Some of the more important global variables present in the system along with their values and a brief description are:

Variable Description CharacterConstants A pool dictionary. CharacterConstants associate names with special character values such as: carriage return, line feed, escape, or form feed. Clipboard The ClipboardManager that is used to transfer data between windows or applications usually through copy, cut, and paste operations. CurrentProcess The Process that is currently running. Cursor A CursorManager used to store the state of the cursor.

Disk An instance of the class Directory that represents the directory that was current when the image was started. For the truly current directory, evaluate the expression: Direc tory c u rrent. ListFont A Font used as the default font for list panes. Notifier The single instance of NotificationManager that dispatches events to windows. Processor The single instance of ProcessScheduler of the system.

Smalltalk The single instance of SystemDictionary.

Visual Smalltalk Enterprise Language Reference 309 CHAPTER 16 System Classes

Variable Description Sources An Array containing file streams for accessing Smalltalk source code. The first entry is the sources file. The second entry is the change log. SysFont The default Font used for text displayed anywhere other than list panes or text panes (for example, button labels). TextFont A Font used as the default font for text panes. Transcript A TranscriptWindow which is the Transcript, used primarily for system messages. You can also send messages to Transcript to show debugging information.

A dictionary contained in a global variable can be used as a pool. You can create a new pool by evaluating an expression such as: Smalltalk at: #MyPool put: Dictionary new You add pool variables by evaluating an expression such as: MyPool at: 'Age' put: 29 Several pools are available in the base Visual Smalltalk environment. To examine the contents of a pool, select the name of the pool and click on Inspect It in the Smalltalk menu. For example, CharacterConstants is a pool associating names to such character values as carriage return and escape. The keys of this dictionary are descriptive strings, and the values are the associated instances of Characters. ClassReader A ClassReader is used for writing all or part of the source code of a class to a file. The instance variable class contains the class that ClassReader processes. ClassReader uses the following instance methods to manage the source code for a class: fileInFrom: aStream Reads chunks from aStream until an empty chunk (a single '!') is found. Each chunk is compiled as a method for the class described by the receiver, and the method source code is logged to the change log. fileOut Writes the source for the class (including the class definition, instance methods, and class methods) in chunk

310 Visual Smalltalk Enterprise Language Reference CompiledMethod

file format to a file. The filename is the class name truncated to the first eight characters, and the filename extension .CLS is added. fileOut: aFileName Writes the source for the class (including the class definition, instance methods, and class methods) in chunk file format to aFileName. fileOutAll: aFileName Writes the source for the class and all of its subclasses (including the class definitions, instance methods, and class methods) in chunk file format to aFileName. fileOutMethod: aSelector Writes the source for aSelector in chunk file format to a file named aSelector. The filename is truncated to the first eight characters, and the filename extension .MTH is added. fileOutMethod: aSelector on: aStream Files out the method aSelector for the class described by the receiver to aStream, in chunk format. fileOutOn: aStream Files out all the methods for the class described by the receiver to aStream in chunk format. CompiledMethod A CompiledMethod is produced by the Visual Smalltalk compiler and contains the compiled code of a Smalltalk method. Class CompiledMethod has an instance variable, sourceObject, which indicates where the source code for a method is located. If the source is in one of the files that Visual Smalltalk maintains (CHANGE.LOG, SOURCES.SML, or a Smalltalk library), then sourceObject is an Integer and is maintained by various methods in CompiledMethod (source, sourceString, sourceIndex). If you want to create some other mechanism for maintaining source code, you can set the sourceObject instance variable (using sourceObject:) to be any object that responds to the message asString. When the source code for a method is requested, the sourceObject variable will be sent the message asString, and the result of that message will be used as the source code. Note also that even though the source code for some of the methods in class CompiledMethod is not visible, the ones related to a method’s source code are visible.

Visual Smalltalk Enterprise Language Reference 311 CHAPTER 16 System Classes Message Class Message defines a data structure with an Array of message arguments, a message selector, and a message receiver to describe a Smalltalk message. A message can be performed anytime. For example, when an undefined message is encountered during execution, the virtual machine passes an instance of class Message describing the undefined message to the method doesNotUnderstand: in class Object, which in turn displays an appropriate error message in the walkback window. Behavior Class Behavior is the abstract class that defines and implements the common protocol for all the classes and metaclasses in Smalltalk. Behavior provides methods that support source code access, compilation, object creation, and class hierarchy access. This class has two subclasses: Class and MetaClass. Event Manager The EventManager provides the fundamental mechanisms for managing events, including the methods for maintaining event tables. While the event management methods can be replicated in other classes, as they have been in a few cases, it is generally preferable to simply create a class under EventManager, if the class needs to make use of these services. This is the reason for recommending throughout the documentation that you create many of your application model classes as subclasses of EventManager. Three major system subclasses make use of these services: •The SessionModel subclass handles a number of items used in starting and shutting down an application. • Instances of the SharedValue subclass trigger a changed event whenever their values change, providing an event triggering mechanism easily shared among objects. • Instances of Timer trigger events at set intervals. Instructions for using the event system in your application are covered in earlier chapters, especially in Basic Building Blocks in chapter 2. The necessary methods typically have default implementations in Object, which you reimplement in your application classes as required.

312 Visual Smalltalk Enterprise Language Reference Event Manager

Event table management methods do not usually need to be reimplemented, unless you have specific reasons not to build an event triggering class a class that already implements them. Managing Event Tables When an event handler is registered with a triggering object, the handler is stored in the object’s event table. Unless the object is a persistent object, such as a class, the event table requires some management in order to release the object for garbage collection. If the references to the object’s event table are not removed, the object is not reclaimed. It is easy for such persistent objects to multiply, causing the image to grow far beyond a reasonable size. Most event-triggering objects are created in subclasses of Window, ApplicationCoordinator, EventManager, or PARTSNonvisualPart. These classes have methods in place to allocate and manage their event tables automatically, and so subclasses do not need to do anything extra. Most other objects, on the other hand, if they trigger events at all and register event handlers, use default methods defined under Object. If your application uses these objects as event triggerers, you need to make provision for deallocating the event table. There are two ways to manage the event table for an object: • You can explicitly release the event table using the release method, defined in Object. This approach simply requires that the triggering object receive the release message at some time during its life. • You can define mechanisms for automatically managing the event table, like those used in TopPane, SubPane, ApplicationCoordinator, and EventManager. To implement automatic event table management for a class, you need to allocate the event table and provide a few accessor methods. The methods as defined in EventManager are: eventTable Answers the event table. If there is no event table, answers an empty table but does not save it. eventTableForEdit Answers and, if necessary, creates and saves the event table. releaseEventTable Breaks the connection between the object and its event table.

Visual Smalltalk Enterprise Language Reference 313 CHAPTER 16 System Classes

The easiest way to get a local event table is to create a subclass of EventManager or some other class that already implements local event table management. The event table itself is implemented as an IdentityDictionary and stored in the instance variable handlers. SessionModel The class SessionModel models a Visual Smalltalk session. It notes when Smalltalk starts up, shuts down, and saves the image. Only one instance of SessionModel exists; it can be accessed by sending the message current to the class SessionModel. Other useful messages are: saveSession Saves the image to the default image file. exitSession Terminates Visual Smalltalk and exits to the operating system. The class SessionModel generates the following events: startup Just after Visual Smalltalk has started. started After Visual Smalltalk has started and all initialization has taken place. aboutToSaveImage Just before the image is saved. savedImage Just after the image is saved, and before execution continues. shutdown Just before Visual Smalltalk exits. smalltalkLibraryBound: The specified Smalltalk library was just bound. objectLibraryBound: Synonym for smalltalkLibraryBound:, retained for backward compatibility.

314 Visual Smalltalk Enterprise Language Reference ClipboardManager

ServiceRegistry Instances of the class ServiceRegistry manage information about specific features that are available in the current Visual Smalltalk environment. The services registered may describe operating system features, bound Smalltalk libraries, the presence of a class or a method, or any number of services you might want to refer to in your application. Each service is associated with a name. For example, the file format, data types, or coordinate system of a given platform can be registered as services with an instance of ServiceRegistry, and then called upon as needed. Applications that do so consistently can be more easily ported across platforms. The following messages are useful: globalRegistry This message to the class ServiceRegistry returns the instance of the receiver that is used as the root of the registry hierarchy. serviceNamed:ifNone: Returns the service registered under the specified service name. If no service is registered under that name, returns the result of evaluating the specified exception block. register:withName:version: Registers with the receiver the given version of the service with the specified name. ClipboardManager ClipboardManager provides data transfer between Visual Smalltalk and the host system clipboard. The global variable Clipboard is the single instance of ClipboardManager. The following are the principal public instance methods: close Close the clipboard, if opened. containsFormat: aCfConstant Answer true if the clipboard contains data in the format described by aCfConstant, a constant from the OperatingSystemConstants pool dictionary. getBitmap Open the clipboard and answer an instance of Bitmap from the clipboard.

Visual Smalltalk Enterprise Language Reference 315 CHAPTER 16 System Classes

getBitmapWidth: aWidth height: aHeight Open the clipboard and answer an instance of Bitmap clipped to width of aWidth and height of aHeight from the clipboard. getMetaFile Get a metafile from the clipboard. Answer an instance of StoredPicture. getString Answer the contents of the clipboard as a string, or an empty string if the clipboard is empty or cannot render a string. open Open the clipboard. setBitmap: aBitmap Copy aBitmap to the clipboard. setMetaFile: aStoredPicture Set the contents of the clipboard to be a metafile. setString: aString Set the contents of the clipboard to aString. Object Finalization Visual Smalltalk uses finalization to ensure that operating system resources are released, even when the programmer forgets to explicitly release it. In particular, finalization is used for ExternalAddress, Icon, and Bitmap objects, and to garbage collect Symbols. Finalization is also used to garbage collect event handlers for objects that do have an explicit event handler instance variable, and to allow properties to be attached to any object and still be properly garbage collected. You can use the finalization mechanism in application programs as well. As explained in the following discussion, this is particularly useful to applications that use external operating system resources, such as memory allocation. What Finalization Does The basic finalization mechanism allows the programmer to specify some action to take place before an object is garbage collected. When the garbage collector detects a finalizable object, it first sends it the message finalize instead of deallocating the object. The finalize method for that object does whatever

316 Visual Smalltalk Enterprise Language Reference Object Finalization

“cleanup” is appropriate for that kind of object. After completing the finalization processing, the object becomes eligible for deallocation by the garbage collector if it is still unreferenced. Note that the system makes no temporal guarantees concerning garbage collection and finalization. There is an indeterminate, and possibly long, period of time between eliminating the last reference to an object and its garbage collection/finalization detection. Similary, there is an indeterminate period of time between the detection that an object needs to be finalized and the actual send of a finalize message. For this reason, finalization should not be used as a primary mechanism for resource recovery. Whereever possible, application code should explicitly recover resources when they are logically no longer needed. Finalization can then be used as a backup mechanism. A related but separate feature is the implementation of weak pointers. Weak pointers work like any other object pointer, except that if the only pointers to an object are weak pointers, then that object is garbage collected. This allows for convenient implementation of things like caches. A cache can point at its cached objects, but if the cache is the only object in the system that points at a cached object, then the cached object will be garbage collected. Basic Finalization Basic methods that support finalization are implemented in class Object. Basic Support needsFinalization Registers the receiver so that when the garbage collector determines that the object is not connected to the graph of live objects, i.e. it is going to be collected, the message finalize will be sent instead. After the object processes the finalize message, it will be collected (unless the object re- registers itself in the finalize method). More detail: what actually happens in needsFinalization is that the receiver is added to a WeakRegistry (see the description of WeakRegistry below). Exactly which WeakRegistry the receiver is added to is specified in the finalizationRegistry method. doesNotNeedFinalization De-registers the receiver. Note, it is not necessary to send this message inside of the finalize method of an object. It

Visual Smalltalk Enterprise Language Reference 317 CHAPTER 16 System Classes

has already been de-registered by the time the method gets control. finalizationRegistry Answer a WeakRegistry to be used for holding the receiver. The default (as provided in the finalizationRegistry method in class Object) is the registry returned by sending finalizer to class SystemWeakRegistries (see description of SystemWeakRegistries below). finalize This is the method the user writes to do what needs to be done prior to the garbage collection of the object. This method is typically reimplemented in each class that is interested in finalization. The finalize method in class Object does nothing. hasFinalization Answer whether the receiver is registered for finalization. Garbage Collection Notification notifyWhenFinalizable: anObject This causes the receiver to be sent the message finalize: when the garbage collector determines that anObject (the argument) is finalizable. The message sent is: anInterestedObject finalize: anObject. As in finalization, after this message is processed, the object will be collected unless a notification request is re-registered. doNotNotifyWhenFinalizable: anObject De-registers the notification request. Again, the user doesn't have to send this message in the finalize: method (see below) it has already been done by the time the method is entered. finalize: anObject This is the method that the user writes to do what needs to be done. This method is typically reimplemented in each class that is interested in finalization. The finalize: method in class Object does nothing. If the same object is registered for both basic finalization and for collection notification, or if more than one interested object gets notified, the order of notification is unspecified.

318 Visual Smalltalk Enterprise Language Reference Object Finalization

SystemWeakRegistries The Smalltalk system provides several weak registries for implementing basic finalization, object properties, host system resource management, etc. Of particular interest are two registries: one for basic finalization support, and one for managing external (host system) resources. These two registries are obtained by sending the following class messages to SystemWeakRegistries. finalizer Answer the simple finalization WeakRegistry. externalResources Answer the externalResources WeakRegistry. Finalization WeakRegistry The simple finalization registry sends the message finalize to the objects in the registry, when they are about to be garbage collected. In general, you will not need to use this registry directly, but it is useful to know that it is the default registry. When you send needsFinalization to an object which does not have finalizationRegistry implemented in the object’s class, the object is put in this default registry. ExternalResources WeakRegistry The ExternalResources registry is quite useful for managing external (host operating system) resources, such as Bitmaps and Icons. In addition to sending finalize to objects in this registry when they are being garbage collected, objects are also sent the following messages: • When the image is about to be saved, each “live” object in the registry is sent the message aboutToSaveImage. • When the program is ending (i.e. when exiting a session), each “live” object in the registry is sent the message aboutToExitSession. • When a program has just started (i.e. when starting a session), each “live” object in the registry is sent the message startingSession. This gives you an opportunity to take appropriate action on the host system resources at these critical times. For example, in Bitmap, aboutToSaveImage copies the actual bits of the bitmap from the host system into the Smalltalk bitmap object, andaboutToExitSession releases the host system bitmap.

Visual Smalltalk Enterprise Language Reference 319 CHAPTER 16 System Classes

These three methods are implemented in class Object, with default action to do nothing, so you can implement whichever ones are appropriate for the external resource being managed. A class that manages a host resource will typically have methods that look something like these: finalizationRegistry ^SystemWeakRegistries externalResources create “or whatever method actually creates the host system resource” . . . . self needsFinalization. . . . . finalize ^self release aboutToSaveImage ^self archive aboutToExitSession ^self release startingSession ^self invalidate Finalization in ExternalAddresses There is no new public protocol for ExternalAddress nor its subclasses. If an instance of a subclass of ExternalAddress gets garbage collected, then the associated system memory is released, if it has not already been explicitly released. We still strongly recommend that external addresses be explicitly released when they are no longer needed. It is not a good practice to rely on finalization to release operating system resources. As explained earlier, the delay before finalizing and garbage collecting can be a problem. Instances of ExternalHeapAddress will send needsFinalization when the OS memory is allocated. The finalize method releases the OS memory. In the release method simply returns, if the handle is cleared. When the OS memory is released (either explicitly via a call to release or in the finalize method), the value of the receiver’s handle is cleared so that subsequent attempts to release the memory will not cause an error.

320 Visual Smalltalk Enterprise Language Reference Object Finalization

Instances of ExternalGlobalAddress work the same way, except that memory that is “passed off” to another process must not be finalized. This happens, for example, when setting a value in the clipboard, or when passing DDE data. The code that allocates this memory must send doesNotNeedFinalization to these instances. Basic Weak Pointers The programmer must send doesNotNeedFinalization for memory that is passed to another process. However, because this memory is typically allocated using methods that are specific to that kind of memory, Visual Smalltalk handles this by automatically sending doesNotNeedFinalization. WeakRegistry There are two classes underlying the basic finalization support methods described above: WeakRegistry and WeakKeyedRegistry. Applications generally do not need to use these classes directly, since the finalization methods in Object and SystemWeakRegistries are sufficient. A weak registry is used to keep track of a collection of objects to be finalized. The basic finalization facilities are implemented using WeakRegistry and WeakKeyedRegistry. A weak registry is like a set together with an action which is evaluated each time an element of the set becomes finalizable. When the action is evaluated, the object being finalized is passed as the argument to the action. Objects may be added, iterated over, and removed from a weak registry, just like a set. For good examples of how to use weak registries, browse the methods in SystemWeakRegistries. WeakRegistry Protocol The following two messages are used to set up a weak registry. action Answer the action that is evaluated when an object managed by the receiver is rescued. action: anEvaluableAction Set the action that is evaluated when an object managed by the receiver is rescued to anEvaluableAction. The following messages are used for adding, iterating on, and removing objects in a weak registry. add: anObject Add anObject to the registry.

Visual Smalltalk Enterprise Language Reference 321 CHAPTER 16 System Classes

do: aBlock Evaluate aBlock with each object of the receiver as its argument. includes: anObject Answers true if the receiver includes anObject, otherwise answers false. remove: anObject Remove anObject from the registry. remove: anObject ifAbsent: aBlock Remove anObject from the registry. WeakKeyedRegistry A WeakKeyedRegistry is like a dictionary, it allowing you to associate an arbitrary value with an object (the key). When the action for a weak keyed registry is evaluated, the argument to the action is an Association whose key is the object being finalized and the value is its associated value (as set via at:put: or at:ifAbsentPut:). WeakKeyedRegistry has the following public protocol, in addition to the protocol it inherits from WeakRegistry. associationsDo: aBlock Evaluate aBlock with each association of the receiver as its argument. at: anObject ifAbsent: aBlock Answer the value associated with anObject if one exists, otherwise answer the value of aBlock. at: anObject ifAbsentPut: aBlock Answer an value associated with anObject. If not found, add anObject whose value is given by the result of evaluating aBlock. at: anObject put: aValue Add anObject to the receiver and associate it with aValue. removeKey: anObject ifAbsent: aBlock Remove anObject from the registry if it exists, otherwise evaluate aBlock.

322 Visual Smalltalk Enterprise Language Reference Weak Pointers

Weak Pointers The Smalltalk virtual machine garbage collector efficiently and frequently recycles memory from objects no longer in use. It does this by dividing objects into live objects (which are kept) and dead objects (which are thrown away). There is no gray area. This makes it difficult (impossible) to efficiently implement things such as caches or lookup tables of objects that are allowed to be garbage collected. The object references in the cache or lookup table keep all of the objects within the table forever alive. Smalltalk objects contain instance slots that hold references to other smalltalk objects. The garbage collector logically computes the transitive closure of all objects reachable from a set of root smalltalk and virtual machine objects via these references. These are collectively known as the live objects. The remaining objects are the garbage objects and they are collected and their memory released. Weak pointers introduces a new type of object reference called a weak pointer object reference. It differs from the usual type of object pointer reference (referred here as a “strong pointer object reference”) by its effect on the Visual Smalltalk garbage collector. Weak pointer objects are indexable objects (arrays) that contain only weak pointer object references (with the exception of the reference to its method dictionary array). Weak pointer object references are not used in computing the transitive closure of reachable objects. This allows an object to be garbage collected if either no path exists to it from the root objects or all paths to it containweak pointer object references. When an object is garbage collected that has weak pointer object references to it, the slots that contain such references are changed to refer to a distinguished object (and hence a root object) known as the residue which is the sole instance of the class ResidueObject. The residue is needed to preserve correctness in weak data structures that contain weak object pointer references such as weak sets. Consider a weak set that contains the sole reference to another object. When the garbage collector throws the object away, the slot that contains the reference needs to be changed to something. Naively it seems that turning the reference to nil would work, except that sets are hashed structures that use nil as the termination of the lookup algorithms. Turning a slot to nil will most likely break the weak set. Therefore the distinguished object is used.

Visual Smalltalk Enterprise Language Reference 323 CHAPTER 16 System Classes

From the point of view of the virtual machine, any indexable object is dynamically changeable from a weak pointer object to a normal object and back. This is done via a new primitive. Smalltalk Extensions for Weak Pointers While the virtual machine views any indexable object as dynamically changeable to and from a weak pointer object, the object must be designed to do so at the Smalltalk level. For most objects it would be an error to turn it into a weak pointer object, because the object is not designed to have its instance slot references unpredictably changed to the residue. Objects for which weak pointer object references make sense implement the following method: makeWeakArray: aBoolean Set the state of the receiver according to the value of the argument. Answer the previous weak reference state as a boolean. If the weak reference state is true, then all references in the receiver are weak pointer references, otherwise they are normal pointer references. Objects exclusively referenced by weak pointers can be garbage collected and the weak references are changed to the distinguished objected: residue. The receiver must be an indexable pointer object. If the weak reference state is true, then all references in the receiver are weak pointer references, otherwise they are normal pointer references. Objects exclusively referenced by weak pointers can be garbage collected and the weak references are changed to the distinguished object ResidueObject. The new class ResidueObject is added as a subclass of Object. The following methods are added to Object and ResidueObject. isResidue Answer true for the residue object, and false for all others. isResidueOrNil Answer true for the residue object and nil, and false for all others.

324 Visual Smalltalk Enterprise Language Reference CHAPTER National Language 17 Support Overview Visual Smalltalk provides full National Language Support (NLS) capability. This feature allows you to write international applications in Visual Smalltalk, without requiring changes to the application source code for use in different countries. The application appears as if it is specifically written in the language native to the country in which it is being used, with all presentation text and country-specific formatting of date and time displayed correctly in the native language. The following NLS features are supported in Visual Smalltalk: • Cultural-dependent formatting of information such as time and date • Cultural-dependent text comparisons for sorting characters and strings • Full support for Double-Byte Character Set (DBCS) • Ability to program in the native language • A method for separating language-specific text from the application code and loading at runtime Visual Smalltalk provides the capability to program in your native language, including Latin alphabet languages such as English, French, and German, and also Far East languages such as Japanese, Chinese, and Korean. You can write programs with class names, message selectors, variable names, etc. in the native languages including those using the double-byte caracter set.

NOTE: If you want your code to be portable (code that can be compiled on any system irrespective of country or language setting), the standard 7-bit ASCII characters should be used.

Visual Smalltalk Enterprise Language Reference 325 CHAPTER 17 National Language Support Host System Dependencies The Visual Smalltalk NLS feature is designed to work in association with the implementation of NLS on the host operating system platform, making the host platform capabilities and settings accessible to the Smalltalk programmer. Windows 3.x uses the 8-bit ANSI character set for Latin alphabet languages. This allows representation of up to 256 characters. The Far East versions of Windows use the double-byte character set (DBCS) and allow representation of up to 65,535 characters, of which the first 256 characters primarily reflect the ANSI set. Windows NT uses a single universal 16-bit wide Unicode character set for all the languages in the world. This allows representation of up to 65,535 characters. Unicode includes the characters from all major languages in the world (including the Far East languages that require double-byte character support in Windows 3.x) as well as technical symbols and special characters in modern computer use worldwide. However, Visual Smalltalk does not support the Unicode character set that is available in Windows NT. Only the ANSI character set is supported. Aspects of the system behavior are controlled by the current country and language settings. On Windows systems, national language configuration information is specified in the Windows Control Panel and Windows initialization files, such as the win.ini profile definition. On OS/2, national language configuration information is specified in COUNTRY.SYS and in the OS/2 Control Panel and OS/2 initialization files such as the OS2.INI profile definition. The information in COUNTRY.SYS is the result of the country and language settings in CONFIG.SYS and is initialized by OS/2 on power-up.

326 Visual Smalltalk Enterprise Language Reference Developing a Multinational Application

Developing a Multinational Application Applications that will be used in different countries must be designed to accommodate translation, both of the language and of data formats. The NLS feature provides mechanisms that help you develop translatable applications. The operating system environment provides configuration settings that indicate the appropriate formatting of such values. These environment settings are accessible in Smalltalk through the global variable NationalLanguage, an instance of NationalLanguageSupport. Classes provided in the base environment, such as Date and Time, use the current system settings to control their representation in string form. On Windows systems, national language selection is provided by the installed language module. This is based on the country and language selected during installation or through the Control Panel. The language module defines mapping of a set of characters onto ordinal values, called code points. On OS/2 systems, national language selection is provided by code pages. A code page is a mapping of a set of characters onto the code point ordinal values. Most code points define the same code point assignments for the standard 7-bit ASCII characters, but differ in their assignments of characters to code points in the range of [128..255]. For example, most Latin alphabet languages are supported by a set of 256 characters, comprising the ANSI character set. This character set is a single-byte character set; every character can be encoded in a single byte. Other languages, such as Chinese, Japanese and Korean, require more than 256 characters. These languages use a double-byte character set that assigns characters to code-point values in the range [256..65535]. A character with a code-point value of 256 or greater is referred to as a double-byte character, since it requires two bytes to encode its code-point value. The installed language also determines the collating sequence that is used for string and character comparisons using the Smalltalk relational operators <, >, <=, and >=.

Visual Smalltalk Enterprise Language Reference 327 CHAPTER 17 National Language Support Separating Text Strings From Application Code To develop a multinational application, you must manage text strings separately from your application code. Separating the translatable strings into a separate data resource allows the text to be translated without changing the code that uses it. The NLS feature that supports string separation is based on pool dictionaries. As you develop your application, create one or more dictionaries containing your translatable strings. You include as pool dictionaries in your application classes wherever you need to use a translatable string. Your code then references the dictionary by variable name to reference this string. Information is often presented by an application as a combination of predefined message text and data values. When you create a translatable application, be aware that your application may be translated into a language with a different sentence structure. Consequently, avoid constructing messages by concatenating fragments of message text. To support translation, you should define a template for the message that contains syntactic markers indicating where parameter values will be substituted at execution time. For example, you can use “%” as a parameter placeholder in your message template. Your program can then construct the message at execution time by substituting the appropriate values into the parameter slots in the message template. When a message is translated, it may result in text that is either longer or shorter than the original text. Anticipate such changes when you design the layout of your application windows. One approach is to make the size and position of the elements in your window large enough for all translations. Another approach is to include logic in your application to compute an appropriate window layout for the text strings as they are used. When an application is developed, one or more dictionaries can be created to contain the application’s translatable strings. Such a string dictionary is used as a pool dictionary by all application classes that require access to the translatable text strings. Each entry in a pool dictionary has a string key that is the name of the pool variable. The value of a string dictionary entry is the actual string that you will use in your application. Pool variable names must conform to the Smalltalk syntax rules for global identifiers (that is, an uppercase letter followed by zero or more alphanumeric characters). The pool variable name is then used in methods to reference the actual string.

328 Visual Smalltalk Enterprise Language Reference Separating Text Strings From Application Code

The specification of the translatable strings is maintained separately from your application in the form of string resources. The application string dictionaries can be loaded from either the text definition of the string resources or from compiled string resources in your application. Refer to the Visual Smalltalk Enterprise Language Reference for additional information on managing string dictionaries. The NLS Application Development Process The general process of developing a multinational application in Visual Smalltalk using NLS features is described in the following steps (see figures 17-1 and 17-2, which illustrate each step of the process). Also refer to the puzzle15 program provided in the EXAMPLES\PUZZLE15 directory. The puzzle15 program is fully enabled with these NLS features and is provided as an example of this process. 1 Create a global dictionary to contain the translatable text. The dictionary will be used as a pool dictionary in your application classes. 2 Create a text file containing the application text definitions in the standard resource string table format. Resource String Tables are described later in this chapter. 3 Load the application text into your string dictionary using StringDictionaryReader. 4 As you develop your application, declare your string dictionary as a pool dictionary in all the classes that need to reference your application text. Instead of writing string literals in methods, refer to a translatable string using the appropriate pool variable name. You can add new strings or change the existing text in the string dictionary at any time during development, simply by editing the application text definition file and reloading it. This allows you to maintain a hardcopy of the current state of the application text and to associate comments describing the purpose of each message to aid its translation into a different language in the future. 5 Translate the application text definition file for all the different languages that your application is to support. 6 If you want to package the application text into resources attached to your .EXE file or to a DLL, compile all the text resource definition files using the Resource Compiler and add the resulting data resources to your modules.

Visual Smalltalk Enterprise Language Reference 329

CHAPTER 17 National Language Support

Each message entry in a string table consists of the pool variable name by which the message will be referenced in your Visual Smalltalk application classes, a string constant defining the actual text string, and an optional comment describing the purpose of the string. The pool variable name must be a legal Smalltalk global variable name: the first character must be an uppercase letter, followed by zero or more alphanumeric characters. The comment, which can be associated with each text string, can be used to provide information to a translator describing the purpose of the string. Once you have created a string resource definition file, you can load the translatable strings into your application string dictionary using StringDictionaryReader. The following example shows how to create and load a pool dictionary for your application strings: AppText := Dictionary new. StringDictionaryReader fill: AppText fromStringTable: 'AppTxtUS.RC'. The strings from the resource definition file are loaded into the dictionary with the pool variable name as the key and the string itself as the value. Once you have loaded your string dictionary, you can use it as a pool dictionary in your application classes. To reference a translatable string in a method, use the pool variable name for the string that you defined in the resource definition file. The following example shows how the pool variable CloseMessage can be used in an application method. When the processClose method shown below is executed, the message box displays the actual text string: Do you really want to close the application? processClose (MessageBox confirm: CloseMessage) ifTrue: [ self exit ]. You can add new strings or change the text in your application string dictionary at any time simply by editing the text definition file and reloading it into your pool dictionary. This method ensures that you maintain a hardcopy of the current state of the application text as you develop your application. It is a good practice to add a comment when you define a new string. Describe its purpose and note any special considerations that would help a translator to correctly translate the string into different languages.

332 Visual Smalltalk Enterprise Language Reference Separating Text Strings From Application Code

Managing Text Strings as Compiled Resources The other alternative for maintaining translatable strings is to add them in compiled resource form to your application .EXE or to a DLL. This method is probably more appropriate to use when you are ready to deliver a final version of your multinational application than during initial application development, when the text file form described in the previous section is more convenient for making changes and additions to your text. Compiling the text definition of your string resources into compiled resources and adding these to your application .EXE or to a DLL requires using the Resource Compiler provided in the Software Development Kit (SDK). The process is described in detail in the SDK documentation. To load a pool variable from a compiled resource, StringDictionaryReader needs to know the resource identifier of each entry in the pool dictionary. An ID dictionary is used to associate the pool variable names in the string dictionary with the resource identifiers of their compiled string resources, since the pool variable names that are used when loading the text resource definition file are not available in the compiled resources. The ID dictionary is created by the developer when the text resource definition is complete and ready to be compiled. It is used at the time that the string dictionary in the application is loaded from the resources. The StringDictionaryReader class method createIdDictionary: creates an ID dictionary from the resource header file used to compile a resource definition. The following is an example of what a resource header file contains: #define WindowTitle 1000 #define MenuFile 1010 #define MenuEdit 1020 ... #define CloseMessage 2000 The resource header file uses the #define command of the C preprocessor syntax . The defined symbol is the pool variable name of a string resource from your text definition file. The integer value assigned to the pool variable name is the resource identifier assigned to this string resource and by which the compiled resource is accessed. You should create the ID dictionary from the same file used to compile your string resources.

Visual Smalltalk Enterprise Language Reference 333 CHAPTER 17 National Language Support

The StringDictionaryReader class method fill:fromModule:idDictionary: fills an application pool dictionary from the compiled string resources in the .EXE or in a DLL. The ID dictionary is used to determine the resource identifier of the string resource to load into each pool variable in the string dictionary. The following is an example of how the application pool dictionary AppText would be filled from the DLL module AppTxtUS using the string ids defined in the header file APPTXT.H: | anIdDictionary | anIdDictionary := StringDictionaryReader createIdDictionary:'APPTXT.H' . StringDictionaryReader fill: AppText fromModule: 'AppTxtUS.DLL' idDictionary: anIdDictionary. The ID dictionary can be created at the time the string dictionary is loaded from the compiled resources or it can be prebuilt. The ObjectFiler capability may be used to store a prebuilt ID dictionary in an external file when not being used, and loaded back into the Visual Smalltalk image when needed (see chapter 10). This way, the dictionary does not have to reside in the image and can be packaged with the rest of the application files for delivery. The ID dictionary can be removed from the image once the string dictionary is loaded if you do not plan to reload the application text again. However, if you wish to create an application that can dynamically change its language, you may wish to keep the ID dictionary in the image and provide a user interface that allows the user to dynamically reload the application text from a one of a set of resource DLLs containing your application text in different languages. If you have a large number of infrequently used messages, you can reduce the memory requirements of your application by loading individual messages from string resources only when needed. For example, this may be appropriate when your application has a large number of error messages that are not needed during normal processing. To load a single string resource, you send the String class message fromModule:id:, where the argument to id: is the integer resource identifier of a compiled string resource.

334 Visual Smalltalk Enterprise Language Reference Text Comparison, Sorting, and Casing

Accessing System NLS Settings The global variable, NationalLanguage, is the sole instance of the class NationalLanguageSupport. Messages can be sent to NationalLanguage to obtain the current values of various NLS properties from the host environment. The messages country and either countryName (on Windows) or codePage (on OS/2) can be sent to find out the current country and language settings of the system. NationalLanguage country. NationalLanguage countryName NationalLanguage codePage. Culture-Dependent Formatting The conventions for representing data values are different in many countries and languages. Data types with country-dependent formatting include dates, times, numbers, and monetary amounts. Messages can be sent to NationalLanguage to obtain the current system values of various national language properties that determine country-specific formatting, such as date, time, currency, and number formatting. NationalLanguage dateFormat. NationalLanguage dateSeparator. NationalLanguage timeFormat. NationalLanguage timeSeparator. NationalLanguage currencyFormat. NationalLanguage currency. NationalLanguage decimalPlace. NationalLanguage decimalSeparator. The Date and Time classes are sensitive to NationalLanguage so that the print messages sent to them answer with the culturally correct format. Text Comparison, Sorting, and Casing Character and string comparisons provided by the binary operators <, >, <=, and >= use the country-specific collating sequence determined by the current country and language settings of the host system. This is different than in previous versions, in which character and string comparisons were based solely on the character code value.

Visual Smalltalk Enterprise Language Reference 335 CHAPTER 17 National Language Support

Casing functions on strings and characters test for and convert between upper and lowercase letters. In Visual Smalltalk, these methods are implemented using operating system functions so that they are sensitive to the current country and language system settings, rather than being hardwired to 7-bit ASCII character code values as in previous versions. Character and String Support Support for double-byte characters and strings is provided by several classes. Characters A Character object represents a single character and is defined by a character code value (code point). A character with a code-point value in the range [0..255] can be encoded in one byte and is referred to as a single-byte character. A character with a code- point value in the range [256..65535] requires two bytes to encode its value and is therefore referred to as a double-byte character. aCharacter isSingleByte aCharacter isDoubleByte The mapping between characters and code point values is defined by the language module installed via the Control Panel program. The character predicate message such as isLetter, isDigit, isAlphaNumeric, isLowerCase, isUpperCase, etc., has been made sensitive to the language module installed. This is a significant change from before and therefore important to note by definition that only the standard 7-bit ASCII characters are guaranteed to respond the same way for all language modules. Testing for character equality should be done using the = operator. The identity operator == should not be used for this purpose. Because single-byte characters are unique, equality and identity happen to be the same. However, this is not necessarily the case for double-byte characters, where two double-byte characters which are equal because they have the same character code value are not necessarily identical. Evaluate the following expressions one at a time: (Character value: 65) == (Character value: 65) (Character value: 6500) == (Character value: 6500) (Character value: 65) = (Character value: 65) (Character value: 6500) = (Character value: 6500).

336 Visual Smalltalk Enterprise Language Reference Character and String Support

DBCS Characters The DBCS characters are available in the Far East versions of both Windows and OS/2 for languages such as Japanese, Chinese, and Korean that require more then 256 characters. DBCS character encoding requires one byte for characters with code-point values in the range [0..255] and two bytes for characters with code-point value in the range [256..65535]. The common public protocol for class Character is the same for both single-byte characters and double-byte characters. We have simply extended it to include the DBCS character set. Windows NLS support provides API functions to determine whether a single-byte character value is a digit, letter, or an uppercase letter. These functions do not allow double-byte character values. Consequently, we assume that all double-byte characters are capital letters, such that messages isLetter and isUpperCase sent to these characters will return true. Strings A string is an indexed collection of characters, and a String is a single-byte string encoding with each character occupying one byte. A String contains only single-byte characters (with code- point values in the range [0..255] occupying one byte of storage). An instance of class DoubleByteString is a fixed-width double- byte string encoding with each character occupying two bytes. The instance can contain both single-byte characters and double- byte characters (with code-point values in the range [0..65535]). In both cases, an element of the collection is a Character and the size of the string is the number of characters in the collection. The two representations of strings share a common public protocol which provides the uniform abstraction of a string as a sequence of characters. In general, you do not need to know which string representation is involved when you use a string. All messages that can be sent to a string can involve any combination of String and DoubleByteString objects for the receiver and the message arguments. Similarly, a stream on a string works the same in both flavors of string representation. Messages to a string that modify the contents of the receiver, such as inserting a double-byte character into a string, will cause a String to be transformed automatically into a DoubleByteString. You never have to do anything special to ensure that an appropriate representation is used for a string—this is handled automatically by the string itself.

Visual Smalltalk Enterprise Language Reference 337 CHAPTER 17 National Language Support

The cases when you must be aware of the difference between the two string encodings primarily involve interactions with the host operating system through API calls and reading or writing strings from files. These areas are discussed in detail in later sections. Inserting Characters into Strings When a double-byte character is inserted into a single-byte String object, the receiver string mutates into double-byte DoubleByteString encoding. You do not need to take any special action either to anticipate or respond to the change in the string's representation. A DoubleByteString is not automatically compacted to an equivalent single-byte String encoding when editing of its contents results in it containing only single-byte characters. String encoding compaction can be explicitly requested by sending the message asCompactString to a string. The following code shows what happens when a double-byte character is put into a single-byte string, and then replaced by a single-byte character “a”. The message asCompactString then converts it back to a single-byte string. | aString | aString := 'abc' . "aString class = String" aString at: 1 put: aDBCharacter. "aString class = DoubleByteString" aString at: 1 put: $a. "aString class = DoubleByteString" aString := aString asCompactString. "aString class = String" Passing Strings Between Visual Smalltalk and the Host You must be aware of the different string encodings when you make API calls to the host operating system or other-language DLLs. Visual Smalltalk uses a fixed-length normalized encoding for strings: a string uniformly uses either one or two bytes per character to represent its character codes. Accordingly, a string is an instance of either String or DoubleByteString, respectively. Application logic is always expressed in terms of characters, regardless of the encoding. On the double-byte language system, it is important to realize that Visual Smalltalk uses a different string encoding than the host operating system for strings containing double-byte characters. The host operating system uses a variable-length mixed-string encoding for a string that contains one or more double-byte characters: the mixed-string encoding uses one byte for single- byte characters and two bytes for double-byte characters.

338 Visual Smalltalk Enterprise Language Reference Character and String Support

Whenever a string is passed to, or obtained from, the host operating system, it must be converted from the host's mixed string encoding to the normalized representation used within Visual Smalltalk. This may also be the case when you make API calls to a DLL in another language, unless the function that you are calling supports the normalized string encoding used within Visual Smalltalk. To convert strings between the two encoding schemes, you can use the new messages asNormalizedString and asExternalString. You can also use the message asParameter, which answers a mixed string with a null terminator, since this is the standard format expected by many API calls. Whenever an API call is made that passes a string as a parameter or as a field value in a record, the Smalltalk string must be converted to the host’s mixed-string encoding. For a string parameter, the usual API convention of aString asParameter for specifying the argument value automatically handles the conversion of a Smalltalk string to a zero-terminated mixed-string encoding: aExternalStringWithZeroTerminator := aString asParameter. When storing the value of a string into a record field or passing a nonzero-terminated string parameter to an API, the string must first be converted to a mixed-string encoding by sending it the message asExternalString. The length that you specify for such a string is generally expected by the host operating system to be the length in bytes of the mixed string encoding (not the number of characters). The following example shows how a string without a null terminator is passed to an API, along with its length in bytes: | anExternalString | anExternalString := aString asExternalString. GDILibrary getTextExtent: hDC string: anExternalString size: anExternalString size. A normalized Smalltalk string must be obtained from the mixed- string encoding when a string value is returned by an API function by storing the string in a buffer or a record field, or by returning an address to a string in memory. You get a normalized string by sending the message asNormalizedString to the string encoding returned by the API.

Visual Smalltalk Enterprise Language Reference 339 CHAPTER 17 National Language Support

| aString size | aString := String new: 256. size := UserLibrary getWindowText: aWindowHandle text: aString maxLength: aString size. ^(aString copyFrom: 1 to: size) asNormalizedString. All user-defined API methods and ExternalBuffer subclasses should be reviewed to verify that strings are properly converted into mixed-string encoding and returned to normalized Smalltalk strings when passing across the boundary between Visual Smalltalk and the host operating system. This is necessary for applications to execute properly in a double-byte system. Mixed string encodings obtained from asExternalString or asParameter are instances of String that should be treated carefully. They should only be used at the moment when crossing the boundary between Visual Smalltalk and the outside environment. You are responsible for properly quarantining mixed strings that you create or obtain. Once let loose in the normal Visual Smalltalk environment, the mixed string will be interpreted as a normal single-byte string, which will not produce the intended sequence of characters! Symbols A symbol is a fixed-size collection of characters guaranteed to be unique across all symbols in the system. A symbol containing only single-byte characters is an instance of class Symbol, while a symbol that contains one or more double-byte characters is an instance of class DoubleByteSymbol. As with strings, the size of a symbol is the number of characters in the collection. The two symbol representations share the same public protocol. As with strings, you generally do not need to know which representation is used—the two types of symbols behave the same way. Symbol literals and message selectors in expressions and methods can contain single-byte as well as double-byte characters. The Smalltalk syntax definition has been extended to include double- byte symbol literals in message selectors. You can also create a double-byte symbol by sending the message asSymbol to a DoubleByteString instance.

340 Visual Smalltalk Enterprise Language Reference FileStreams

FileStreams In Visual Smalltalk, a FileStream provides access to the contents of a file as a sequence of characters. The host operating system may use mixed-string or fixed-length encoding in text files. Therefore, a file stream must be able to answer a complete single or double-byte character as a result of a next message. To access files containing mixed-string text without degrading FileStream performance on single-byte systems, class MixedFileStream has been introduced. It automatically provides conversion between the external mixed-string encoding and the normalized string representation used within Visual Smalltalk as you read and write text in the file. The public protocol of a MixedFileStream is the same as FileStream. FileStreams with Double-Byte Characters When a stream on a file is opened in a double-byte system, a MixedFileStream is automatically created. A MixedFileStream treats the file as a text stream. Messages to a MixedFileStream, which read the contents of the file, handle interpreting the mixed- string encoding and always return complete characters and normalized strings. For example, the next message answers the next character in the file and can advance the stream position by one or two bytes. Messages to a MixedFileStream which write characters and strings to the file will convert normalized Smalltalk strings into the equivalent mixed-string encoding. The position of a file stream is always the byte offset in the file. Applications written for a double-byte environment should be careful when explicitly manipulating the position of a MixedFileStream. It is generally not safe to do arbitrary arithmetic on a position and use the result to change the position of the stream when the file contains mixed-string text. It is correct to save a position and use that value later to reset the stream position, since this is guaranteed to be correctly positioned on a character. When you compute the difference between two valid positions of a file stream, remember that this value is the byte difference and not necessarily the number of characters contained in the file between the two positions. To back up one character in a file stream on a double-byte system, it is not safe to reset the file stream by using an expression such as:

Visual Smalltalk Enterprise Language Reference 341 CHAPTER 17 National Language Support

aStream position: (aStream position - 1). "Incorrect for MixedFileStream" This expression will incorrectly position a MixedFileStream when the last character read from the stream was a double-byte character. All subsequent text read from this file stream after such an operation is no longer guaranteed to correctly reflect the characters in the file. You should use the new message backupOver: to back up one character in a file stream: [(aChar := aStream next) = stopChar] whileFalse:[ ]. aStream backupOver: aChar. "Correct for MixedFileStream" It is always safe to save the position of a stream and later use the saved position to reset the stream. For example, the following code is correct in both single-byte and double-byte environments: originalPosition := aStream position. " ... read ahead in the stream for some reason ... " aStream position: originalPosition. Binary File Streams The introduction of MixedFileStream class for DBCS support will not be a concern in most cases. The exception is when your file contains binary data and you need to have it treated as a byte stream, even when executing on DBCS systems. The message asByteFileStream can be sent to a newly-opened file stream to ensure that it is a FileStream. This ensures that the next message always returns the next byte in the file. Otherwise, the default file stream will be opened. This default is MixedFileStream on a double-byte system. When reading and writing strings to a binary FileStream on a double-byte system, you must explicitly handle string conversion between mixed and normalized encoding. You can use the messages asExternalString and asNormalizedString for this purpose, as discussed in the section Passing Strings Between Visual Smalltalk and the Host.

342 Visual Smalltalk Enterprise Language Reference Supporting Text in Multiple Languages

Supporting Text in Multiple Languages An application that is designed to supports text in multiple languages can control the decoding of strings containing double- byte characters from the host operating system’s mixed-string encoding into normalized Smalltalk string objects. The normalization operations on strings and the MixedFileStream messages that read text from a mixed-string encoding file are controlled by a lead-bytes array. A lead-byte array is an array of boolean flags, indexed by a lead-byte character code value [1..255]. These values indicate whether this code-point value is a lead-byte value of a double-byte character. You can construct the lead-bytes array yourself or obtain it from NationalLanguage by: "On Windows" aLeadBytesArray := NationalLanguage leadBytes. "On OS/2" aLeadBytesArray := NationalLanguage leadBytesFor: aCountryCodeId codePage: aCodePageId. You can normalize a mixed-string encoding for a language or code page other than the one currently active if you have a lead- bytes array for that language or code page. Send the asNormalizedString: message to the mixed string and provide a lead-bytes flag array: aString := anExternalString asNormalizedString: aLeadBytesArray. You can read a mixed-string encoding from a file that you want to interpret in a language or code page other than the one currently active. Send the message leadBytes: to the MixedFileStream to set the lead-bytes flags that control reading characters from the file: aMixedFileStream leadBytes: aLeadByteArray. aFileStream := aFileStream asMixedFileStream: aLeadByteArray. Subsequent messages sent to this file stream will decode the bytes in the file according to the new lead-bytes array that you have supplied. If your application supports multiple languages, you must design a mechanism for associating the language module or code page with a string instance so that the character values can be

Visual Smalltalk Enterprise Language Reference 343 CHAPTER 17 National Language Support

interpreted as the intended sequence of characters. You must also handle rendering so that the appropriate language is set in the presentation space when you render a character string from a language that is different than the current system language.

344 Visual Smalltalk Enterprise Language Reference CHAPTER Performance 18 Profiler Overview The profiler is a performance-tuning tool for Visual Smalltalk programs. It is a tool to help speed up program execution by identifying potential bottlenecks in the code. There are two general methods used to measure the execution profile of a program. One is the periodic sampling method, also known as passive or statistical profiling. In this approach, the program execution is sampled at every preset time interval, through some hardware timer interrupt mechanism. At each timer interrupt the profile data is captured, and the program is allowed to continue execution. This technique reveals a statistical probability model of the program execution, based on the timer interval and the duration of the run. As with all statistical models, the longer the run, the greater the chances of determining where and in what function of the program most of the time is being spent. However, the periodic sampling method of profiling provides no data at all about how many times a function was executed. The other approach is the continuous sampling method, also known as active profiling. This approach, provides a more detailed map of the execution than the periodic sampling method. The reason is because the program execution gets sampled at each instruction in the code. This technique not only reveals how many times a function is called and the total time spent executing the function, but also the execution tree that provides the sequence in which the code is executed. This method of profiling generates far more data than the previous method and also intrudes on the actual execution time. A program running under the control of the profiler runs much slower than usual. However, because the profiler intrudes on each instruction uniformly, the relative timing information is valuable and appropriate for the intended use.

Visual Smalltalk Enterprise Language Reference 345 CHAPTER 18 Performance Profiler

The continuous sampling method of profiling is useful for monitoring execution of isolated set of functions or a small subset of the program. It is ideally suited for small programs that run for a short duration in terms of seconds or minutes, rather than large programs that run for hours or days. It is this second method of profiling, the continuous sampling method, that the Visual Smalltalk Performance Profiler is based on. The profiler is designed around the architecture that the debugger uses to do controlled execution. It uses a mechanism similar to the debugger single step in which each message-send operation causes a jump into a special trace function where the necessary debugging operation is performed before executing the actual message. The profiler uses this form of single-stepping through a similar trace function in the virtual machine to log profile information about each message-send to a file called PROFILE.LOG. To install the Performance Profiler, select Performance Profiler in the Service Manager, then click Install. How to Use the Profiler Once you have developed your Smalltalk program, and have it working. You will want to try to speed up the program. It is generally the case that most programs spend the bulk of their execution time in a relatively small portion of the underlying code. If your program is small and takes on the order of seconds or minutes to run, then go ahead and run the profiler on it. However, if your program is large and takes hours to run, you will need to divide up your program into small subfunctions. Then, systematically isolate the code to a set of Smalltalk methods or functions and start profiling its execution. You can modify the method by adding the profiling instructions to it and capture the execution profile at program runtime. However, if this code is executed more than once, then the execution profile data in the file PROFILE.LOG will reflect the last time it was executed. Another approach is to evaluate the function in isolation. You can do this by constructing an expression using that function and place it into the profiler code sequence (inside the monitor: block or between the monitorOn and monitorOff instructions) specified in the User Interface section below. Use a systematic approach of divide and conquer, so to speak, and profile as much of your code as necessary, continually improving and reprofiling it. You can repeat this technique until you are satisfied with the programs performance.

346 Visual Smalltalk Enterprise Language Reference User Interface

User Interface The following two sequences show the Smalltalk protocol for monitoring execution of Smalltalk keys. The user interface trace option is turned off, in these cases, because we do not want the profiling to be disrupted by interrupt processing of peripheral activity such as mouse movement or keys being entered on the keyboard. You would only turn it on if your program requires it or if you want to profile the processing of these types of programming interrupts. The following sequence writes the profile report to the Transcript: | p | "get a new profiler" p := Profiler new. "set trace options" p traceUserIF: false. "monitor code in a block" p monitor: [Smalltalk keys]. "produce report on Transcript" p printReportOn: Transcript. The following sequence writes the profile report to a file: | p s | "get a new profiler" p := Profiler new. "set trace options" p traceUserIF: false. "monitor code until next monitorOff" p monitorOn. "this code will be monitored" Smalltalk keys. "turn off code monitoring" p monitorOff. "open a file for printing the report" s := ( File pathName:'profile.rpt' ). "produce report " p printReportOn: s. "close report file" s close. Any expression may be placed in the monitor: block or in between monitorOn and monitorOff to profile its performance. Please note that it may take a good deal of time to compile and produce the report, depending on the complexity of the expression being profiled.

Visual Smalltalk Enterprise Language Reference 347 CHAPTER 18 Performance Profiler Report The profiler generates one type of report from the profile data logged in the file PROFILE.LOG. This report is a formatted representation of the execution tree. At the top is stated the total number of Smalltalk message-sends and the total time it took to execute the given code. The time for writing the execution profile data into the log file is included in the total time. We recommend that you use a fixed-width font to view the report. The report shows the following fields for each line of entry:

Field Description Time Total execution time in seconds % Percentage of the total time spent at that level Freq Total number of invocations of the method % Percentage of the total number of invocations at that level Selector Method name Receiver Class Name of the class receiving the message Method Class Name of the class implementing the method

The report in figure 18-1 shows the result of profiling the execution of Smalltalk keys on a Windows system.

348 Visual Smalltalk Enterprise Language Reference Report

Figure 18-1: Sample Execution Profile Report

Profiler Report Total message sends : 24311 Total time : 6.985 second(s) Sort : Time User I/F : Not Traced Time % Freq % Selector Receiver Class Method Class ------

Entry 0 Level 0 6.985 100 1 50 keys SystemDictionary Dictionary 0.000 0 1 50 monitorOff Profiler Profiler

Entry 1 Level 1 From Entry 0 6.985 100 1 100 keys SystemDictionary Dictionary 6.907 99 1 25 associationsDo: SystemDictionary Dictionary 0.053 1 1 25 new: Set class HashedCollection class 0.000 0 1 25 size SystemDictionary HashedCollection 0.000 0 1 25 keyCollectionClassSystemDictionary Dictionary Entry 2 Level 2 From Entry 1 6.907 100 1 100 associationsDo: SystemDictionary Dictionary 6.907 100 1 50 elementsDo: LinearHashTable LinearHashTable 0.000 0 1 50 contents SystemDictionary HashedCollection

Entry 3 Level 3 From Entry 2 6.907 100 1 100 elementsDo: LinearHashTable LinearHashTable 5.167 75 974 15 [aBlock] ...... 1.322 19 4729 71 at: LinearHashTable Object 0.418 6 974 15 value: OneArgumentBlock OneArgumentBlock 0.000 0 1 0 size LinearHashTable FixedSizeCollection

Entry 4 Level 4 From Entry 3 5.167 100 974 100 [aBlock] ...... 4.837 94 974 50 add: Set HashedCollection 0.330 6 974 50 key Association Association Entry 5 Level 5 From Entry 4 4.837 100 974 100 add: Set HashedCollection 2.887 60 974 33 atKey:put:for: LinearHashTable LinearHashTable 1.486 31 974 33 incrementElementCountSet HashedCollection 0.167 3 974 33 contents Set HashedCollection Entry 6 Level 6 From Entry 5 2.887 100 974 100 atKey:put:for: LinearHashTable LinearHashTable 2.038 71 974 33 findKeyIndex:for: LinearHashTable LinearHashTable 0.291 10 974 33 at: LinearHashTable Object 0.288 10 974 33 at:put: LinearHashTable Object Entry 7 Level 7 From Entry 6 2.038 100 974 100 findKeyIndex:for: LinearHashTable LinearHashTable 0.732 36 974 21 computeHash: Set HashedCollection 0.391 19 1325 29 at: LinearHashTable Object 0.248 12 974 21 \\ SmallInteger SmallInteger 0.235 12 974 21 size LinearHashTable FixedSizeCollection 0.162 8 351 8 compare:candidate:Set HashedCollection

Entry 8 Level 6 From Entry 5 1.486 100 974 100 incrementElementCountSet HashedCollection 1.121 75 974 100 adjustSize Set HashedCollection Entry 9 Level 7 From Entry 8 1.121 100 974 100 adjustSize Set HashedCollection 0.437 39 974 33 loadFactorExceeded:LinearHashTable LinearHashTable 0.216 19 974 33 elementCount Set HashedCollection 0.178 16 974 33 contents Set HashedCollection Entry 10 Level 8 From Entry 7 0.732 100 974 100 computeHash: Set HashedCollection 0.236 32 974 100 hash Symbol Symbol

Entry 11 Level 8 From Entry 9 0.437 100 974 100 loadFactorExceeded:LinearHashTable LinearHashTable 0.161 37 974 100 size LinearHashTable FixedSizeCollection

Visual Smalltalk Enterprise Language Reference 349 CHAPTER 18 Performance Profiler

Entry 12 Level 8 From Entry 7 0.162 100 351 100 compare:candidate:Set HashedCollection 0.069 43 351 100 = Symbol Symbol

Entry 13 Level 2 From Entry 1 0.053 100 1 100 new: Set class HashedCollection class 0.053 100 1 25 initialSize: Set HashedCollection 0.000 0 1 25 allocationForSize:Set class HashedCollection class 0.000 0 1 25 max: SmallInteger Magnitude 0.000 0 1 25 basicNew Set class Behavior Entry 14 Level 3 From Entry 13 0.053 100 1 100 initialSize: Set HashedCollection 0.053 100 1 33 newContents: Set HashedCollection 0.000 0 1 33 contents: Set HashedCollection 0.000 0 1 33 elementCount: Set HashedCollection Entry 15 Level 4 From Entry 14 0.053 100 1 100 newContents: Set HashedCollection 0.053 100 1 33 new: LinearHashTable classHashTable class 0.000 0 1 33 bucketClass Set HashedCollection 0.000 0 1 33 maxLinearSlots Set HashedCollection Entry 16 Level 5 From Entry 15 0.053 100 1 100 new: LinearHashTable classHashTable class 0.053 100 1 50 hashModulusFor: LinearHashTable classHashTable class 0.000 0 1 50 new: Array class Behavior

Entry 17 Level 6 From Entry 16 0.053 100 1 100 hashModulusFor: LinearHashTable classHashTable class 0.053 100 1 100 at: ByteArray Object Entry 18 Level 1 From Entry 0 0.000 0 1 100 monitorOff Profiler Profiler 0.000 0 1 100 profileEnd Profiler Profiler

The report is sorted on the time field to highlight potential problem areas. Each marked Entry N denotes the Nth node in the execution tree, and each marked Level M denotes the Mth level from the root. Each entry is uniquely numbered, and there may be more than one entry at any level in the tree. Figure 18-2 illustrates the execution tree of the report shown in figure 18-1. You will notice a one-to-one correspondence between the entries in the report and the tree nodes. The root node is the top of the tree at Level 0 and Entry 0 in the report. The number on the branches stemming from the root, directly below, indicate the execution frequency of nodes for the message selectors keys and monitorOff at Level 1 and Entry 1 and Entry 10. The nodes below that are for message selectors associationsDo:, new:, size, and profileEnd, at Level 2. This continues on until you end up at a terminating node at message selectors such as size at Level 2 and at: at Level 7 for which there are no entries in the report, other than from the originating node entries from one level above.

350 Visual Smalltalk Enterprise Language Reference Report

Figure 18-2: Sample Execution Profile Tree

a

Visual Smalltalk Enterprise Language Reference 351 CHAPTER 18 Performance Profiler Programming Interface The Performance Profiler employs a two-phase architecture. The first phase is to simply log the execution profile data at runtime. This is done in the virtual machine to minimize performance degradation and provide acceptable timing information. This ensures that the amount of additional processing per Smalltalk message-send due to profiling is very uniform and the timing reflects accurately the relative performance. The second phase is to generate the actual report from the data. This can take a good deal of time in comparison to the execution. Because this is done as a separate task, it does not impact the measurements. Five values are logged for each Smalltalk message-send: • Receiver class • Method selector • Current time stamp • Stack level • Program counter These values are sufficient to infer extensive detail about the program execution, such as: • Method entry • Method exit • Method execution time and its relative percentage • Method execution frequency count and its relative percentage • Message-send tree of the execution. The profiler contains a report writer that generates one type of profile report from the logged execution data. However, the raw data logged in PROFILE.LOG can be processed in many different ways to produce a variety of reports. The method printLog: is available to print the raw profile data, as logged in PROFILE.LOG, in a readable form. Each line represents an entry for one Smalltalk message-send. The five-value entry is printed in the following order with identification tags:

Tag Description Receiver class Method selector Time stamp Stack level Program counter

352 Visual Smalltalk Enterprise Language Reference Programming Interface

The following example illustrates how to use the printLog: method to generate the report. In this example, you save the report under the name profile.rpt in the current directory. | p s | "get a new profiler" p := Profiler new. "open a file for printing the log" s := ( File pathName: 'proflog.rpt' ). "produce report " p printLog: s. "close report file" s close..

Visual Smalltalk Enterprise Language Reference 353

CHAPTER OS Interface and 19 API Calls Overview This chapter discusses classes and features in Visual Smalltalk that allow your application to interface with the underlying operating system platform. The discussion assumes you are already familiar with the concepts and terminology of programming in the Windows and/or OS/2 environments. The materials covered here are not intended to be an explanation of operating system API. For details of the operating system, consult the programmer’s documentation for the particular operating system. API Interface Classes Because the APIs for Windows and OS/2 systems are signicantly different, it is impossible at this level to make Visual Smalltalk entirely portable across these platforms. To improve portability, however, and to help you develop portable applications, Visual Smalltalk employs a set of classes and pools that shield your application as much as possible from the details of the platform specific implentations. Common Interface The following classes are common to all platforms: DynamicDataExchange A DynamicDataExchange instance represents a single Dynamic Data Exchange (DDE) conversation. DynamicDataExchange and its subclasses provide protocol for participating in a DDE conversation as either a client or a server. For more information on DDE, refer to chapter 11, Dynamic Data Exchange (DDE). DynamicLinkLibrary DynamicLinkLibrary is an abstract class that provides the mechanism for Visual Smalltalk to call DLLs. A subclass of DynamicLinkLibrary represents a particular DLL

Visual Smalltalk Enterprise Language Reference 355 CHAPTER 19 OS Interface and API Calls

containing executable procedures (APIs). The subclass DynamicLinkLibrary16 provides functions for accessing 16-bit DLLs, instead of using 32-bit functions ExternalBuffer An ExternalBuffer instance represents a data structure used by the operating system, often corresponding to a C language structure. An ExternalBuffer contains a ByteArray that contains the bytes of the data structure. Class ExternalBuffer has methods for accessing the fields of a structure. ExternalBuffer has a number of subclasses that correspond to the data structures used by Visual Smalltalk. ExternalHandle An ExternalHandle instance contains a 32-bit integer that the operating system uses to identify its own objects, such as window handles and memory handles. OperatingSystemInformation The global variable OperatingSystem is the only instance of class OperatingSystemInformation. It contains information about Visual Smalltalk's use of the host operating system. WindowHandle A subclass of ExternalHandle. Every window object contains a WindowHandle instance in its handle instance variable. Nearly all calls to an operating system window take a WindowHandle as an argument. Class WindowHandle has methods for manipulating windows in operating system specific ways. Most window manipulations should be done through class Window, not WindowHandle. The common interface also includes one global variable: OperatingSystemConstants A pool containing all the #define constants from the Win32s or OS/2 header file, depending on the platform. Windows Specific Interface The following classes are specific to the Windows platform. DeviceContext A subclass of ExternalHandle. Every GraphicsTool object contains a DeviceContext instance in its deviceContext instance variable. A DeviceContext is the first argument to nearly all of Win32s GDI calls.

356 Visual Smalltalk Enterprise Language Reference API Interface Classes

GDIDLL A subclass of DynamicLinkLibrary containing Win32s GDI API calls. KernelDLL A subclass of DynamicLinkLibrary containing Win32s system service API calls. UserDLL A subclass of DynamicLinkLibrary containing Win32s window manager API calls. The following globals are specific to the Windows platform: GDILibrary An instance of GDIDLL, initialized at startup. KernelLibrary An instance of KernelDLL, initialized at startup.

UserLibrary An instance of UserDLL, initialized at startup. VirtualKeyConstants A pool of virtual key constants (such as AfAlt for Alt key). OS/2 Specific Interface The following classes are specific to the OS/2 platform: PMWindowLibraryDLL A subclass of DynamicLinkLibrary containing OS/2 window management API calls. PMGraphicsLibraryDLL A subclass of DynamicLinkLibrary containing OS/2 Graphics Programming Interface (GPI) API calls. DosDLL A subclass of DynamicLinkLibrary containing OS/2 base system API calls. PresentationSpaceHandle A subclass of ExternalHandle. Every GraphicsTool object contains a PresentationSpaceHandle instance in its presentationHandle instance variable. A PresentationSpaceHandle is the first argument to nearly all of OS/2’s GPI calls. The following global objects are specific to the OS/2 platform:

Visual Smalltalk Enterprise Language Reference 357 CHAPTER 19 OS Interface and API Calls

PMWindowLibrary An instance of PMWindowLibraryDLL, initialized at startup. PMGraphicsLibrary An instance of PMGraphicsLibraryDLL, initialized at startup. DosLibrary An instance of DosDLL, initialized at startup. Dynamic Link Libraries and API Calls Any procedure in a Dynamic Link Library (DLL) can be called from Visual Smalltalk. DLL formats are specific to the operating system, however, so calls are not generally portable across platforms. Visual Smalltalk provides classes and methods that wrap many of the Windows and OS/2 DLLs making these easy to call. In addition to these standard API calls, you can add methods for any other DLL call you need, as well as create wrappers for any other DLL. To wrap a DLL, you create a subclass of DynamicLinkLibrary to represent the DLL and add a method for each call. The syntax for writing the calling methods are described in the following sections. You can also look at the methods wrapping standard calls for examples. Making API Calls To call a procedure in a DLL, you first must have a handle to the DLL module. In Visual Smalltalk, this handle is an instance of a subclass of DynamicLinkLibrary. Handles are established for standard Windows or OS/2 DLLs during startup and assigned to global variables, these instances are global variables:

Windows OS/2 GDILibrary PMWindowLibrary KernelLibrary PMGraphicsLibrary UserLibrary DosLibrary

To make an API call to one of these standard DLLs, send a message to the its instance name. If a call

358 Visual Smalltalk Enterprise Language Reference Dynamic Link Libraries and API Calls

If a DLL does not have a global variable representing an instance, you can create an instance by sending open: to the class representing the DLL, a subclass of DynamicLinkLibrary, passing it the name of the DLL file (with the .DLL extension) as the argument. If the class has a class method fileName that answers the name of the DLL, and then send the open message to the DLL class. It is okay to open a DLL more than once, since the file isn’t actually re-opened each time. However, you must free the library the same number of times that you have opened it to unload it from the system (using the close message). Passing Arguments in API Calls The correct kind of objects must be passed as arguments to an API call. For example, some Windows GDI calls take a pointer as an argument. These calls assume the argument is a pointer to a Windows POINT structure. To help in converting Visual Smalltalk objects to the required structures, many objects respond to the message asParameter, which converts the receiver object to a form suitable for passing to an API call. The operating system does not always check the types and values of arguments passed to API calls. Although Visual Smalltalk catches many errors, it is possible to crash Visual Smalltalk by passing an incorrect value to an API call. API Methods The methods in DynamicLinkLibrary subclasses use a special syntax for describing an API call and its arguments. The syntax for an API call method is as follows: messagePattern "comment" where: convention is the calling convention used by the named function. This is either c or api (these two are equivalent), pascal (Windows only), c16, or pascal16. api is a synonym for stdcall, referring to the system convention, and generally any new methods added to call functions in system DLLs can use it. The other conventions are used to call a DLL that was compiled using other calling convention. A DLL

Visual Smalltalk Enterprise Language Reference 359 CHAPTER 19 OS Interface and API Calls

may only contain 16-bit code, requiring use of c16 or pascal16. As an alternative, the class may be defined as a subclass of DynamicLinkLibrary16, in which case c, pascal, and api are interpreted as 16-bit descriptors. Two additional calling conventions are also supported: ole for OLE2 API calls, and som for SOM function calls. These are described in later chapters. APINAME is either the name or the ordinal number of the API. The name can be used only if the DLL’s entry points were exported by name. To specify an ordinal, use the syntax '#nn', where nn is the ordinal number of the API. arg1Type arg2Type ... are the arguments for the API call, one for each argument supplied in the message pattern. The following are the allowable argument types and their descriptions:

Argument Meaning

boolean Four bytes are passed. The object must be a Boolean. This corresponds to type BOOL in C. double Eight bytes are passed. This type is intended for use with double-precision floating-point arguments such as class Float. handle The first four bytes of the object are passed. The object can be a variableByteSubclass and will usually be an ExternalHandle (or one of its subclasses). long Four bytes are passed. The object may be an integer in the range of -2147483648 .. +2147483647 (0x80000000 .. 0x7FFFFFFF), or it can be a byte object, and the first four bytes are passed. This corresponds to type LONG in C. self The object pointer itself is passed. This is used by user-defined DLL functions.

short Four bytes are passed. The object may be an integer in the range of -32768 .. +32767 (0x8000 .. 0x7FFF), or it can be a byte object, and the first two bytes are passed. This corresponds to type SHORT in C. struct The four-byte address of the bytes of the object are passed. The object must be a variableByteSubclass and will usually be an ExternalBuffer. This type is used when the C argument is a pointer, such as a PSZ. structIn A struct pointer argument which is an IN parameter, i.e., the caller makes no changes to the structure. This is a performance optimization of the existing struct argument type.

360 Visual Smalltalk Enterprise Language Reference Dynamic Link Libraries and API Calls

Argument Meaning

structOut A struct pointer argument which is an OUT parameter, i.e., the initial state of the structure is not specified and the caller will set the values. This is a performance optimization of the existing struct argument type. structValue This is a structure argument which is passed by value. For example, a POINTL argument is an 8-byte structure passed by value on the call stack, in contrast to a PPOINTL argument, which is a pointer to a POINTL structure. ulong Four bytes are passed. The object may be a positive integer the range of 0..4294967295 (0xFFFFFFFF), or it can be a byte object, and the first four bytes are passed. This corresponds to type ULONG in C. ushort Four bytes are passed. The object may be a positive integer in the range of 0 to 65535 (0xFFFF), or it can be a byte object and the first two bytes are passed. This corresponds to type USHORT in C.

The nil object is also allowed as an argument and zero bytes are passed. returnType is the type of the return value. The return type must be one of the following:

Return Type Return Value

hresult A 32-bit return value of type HRESULT. This return type is used extensively in OLE, but can also be used in non-OLE API’s. none Is specified if the function does not return a value. This is equivalent to declaring VOID in C.

short A 2-byte Integer, signed ushort A 2-byte Integer, unsigned

boolean A 4-byte Boolean long A 4-byte Integer, signed ulong A 4-byte String, representing an unsigned integer quantity

ulongReturn A 4-byte Integer, unsigned double An 8-byte Float, signed handle A variableByteObject (String) from which an appropriate ExternalHandle can be obtained via fromBytes: (Note: handle is actually the same as ulong)

Visual Smalltalk Enterprise Language Reference 361 CHAPTER 19 OS Interface and API Calls

Here’s an example of a Windows API call method: destroyWindow: aWindowHandle ^self invalidArgument Adding API Calls To add an API call, find the API in the library reference documentation and determine the argument types and return type. Then add a method to the appropriate DynamicLink-Library subclass using the syntax described above. CallBack The CallBack class gives a way for an API that has been called from Smalltalk to call back into Smalltalk. That is, Visual Smalltalk can execute a function outside of Visual Smalltalk, such as an API, that requires some Visual Smalltalk processing before returning to Visual Smalltalk. Using a callback requires at least three methods: • An instance method making the API call • A class method that provides processing when called by the API • A class method that registers the CallBack object Additional methods may be needed to provide additional processing. Installing the CallBack Example The CallBack example is a simple test program. It consists of a DLL file with a single API, CALLBACKTEST, and a few Smalltalk methods. Copy CBTEST.DLL from EXAMPLES\CALLBACK to the Visual Smalltalk directory. Then use File/Install to install CBTEST.ST, also in the CALLBACK directory. Creating a CallBack Usually, you create a subclass of DynamicLinkLibrary for each DLL containing APIs; for this example the subclass is CallBackTestDLL. This subclass contains the Smalltalk methods making the API calls.

362 Visual Smalltalk Enterprise Language Reference CallBack

The API methods are the same as described earlier in this chapter. The test example has a single API: callBackTest: anInteger proc: aCallBack ^self invalidArgument aCallBack, the second method argument, provides the procedure address of the callback function. This address is provided when the CallBack instance is created and registered. The CallBack instance is created by sending the class message: registerMessage: stMessage parameterTypes: aParameterTypeArray returnType: aReturnType callingConvention: aCcType The message arguments are as follows: stMessage The message to be sent when the callback is invoked. aParameterTypeArray An array of argument types. This collection indicates how to convert each procedure parameter into an object. aReturnType The type that is expected to be returned from the callback function. aCcType The API calling convention used for passing the procedure parameters. For CallBackTest, this is done in the test class method:

Visual Smalltalk Enterprise Language Reference 363 CHAPTER 19 OS Interface and API Calls

test "CallBackTest test" | dll aCallBack aMessage anAnswer | dll := CallBackTestDLL open: 'cbtest'. aMessage := Message new receiver: self; selector: #callBack:with:with:with: ; yourself. aCallBack := CallBack registerMessage: aMessage parameterTypes: #( short long ushort ulong ) returnType: #ulong callingConvention: #api. anAnswer := dll callBackTest: 2 proc: aCallBack asParameter. dll close. aCallBack release. ^anAnswer aMessage is the message, callBack:with:with:with:, sent by the API when it calls back into Visual Smalltalk. This message is a class message defined for CallBackTest. The registerMessage:... creates an instance of CallBack and returns a pointer. The pointer is the procedure address of the callback function that is passed to the API requiring it, aCallBack in the API method shown above. The API message is then sent to an instance of the DLL containing the API, named dll in this example, with the CallBack object as an argument. Notice that it is necessary to send the asParameter message to the CallBack object before passing it to the API. The API calling message is defined in the appropriate subclass of DynamicLinkLibrary, in this case CallBackTestDLL. When the CallBack object is no longer needed, it should be released using the release message. A CallBack object needs to be recreated for each Visual Smalltalk session. ExternalBuffer and its Subclasses An ExternalBuffer represents a data structure used by the operating system, often corresponding to a C language structure. ExternalBuffer has one instance variable, contents, which contains eithrer a ByteArray holding the bytes of the data structure, or an ExternalAddress pointing to the bytes of the data structure. When passing an ExternalBuffer as a parameter to an API call, the parameter type should be struct and you should

364 Visual Smalltalk Enterprise Language Reference ExternalBuffer and its Subclasses

always send asParameter to the ExternalBuffer before calling the API. asParameter answers the contents the byte array, and struct passes the address of the byte array to the API. Structures are always passed to APIs as a pointer to the structure. For example, to call GpiLine, the C declaration is: typedef POINTL FAR *PPOINTL; LONG APIENTRY GpiLine(HPS hps, PPOINTL pptlEndPoint); The method in class PMGraphicsLibraryDLL is: line: anHPS pptlEndPoint: aPMPoint and the Smalltalk code to call this API is: PMGraphicsLibrary line: pen handle pptlEndPoint: pmPoint asParameter. Sending the message asParameter to an instance of PMPoint passes a pointer to the contents of the PMPoint object, which is equivalent to what happens in C when you declare a POINTL variable and use the & operator in the API call. ExternalBuffer Subclasses Most subclasses of ExternalBuffer represent a particular operating system specific data structure, including methods for accessing and setting the fields of the structure by name. This allows you to work with a data structure in a manner similar to how you would work with it in C, without worrying about where a field is in the structure or its size. For example, WinLogFont contains information about the Win32 logical font. LOGFONT has a field called lfHeight, so there is a lfHeight method in WinLogFont. Adding an ExternalBuffer Subclass If there is a data structure you want to use that does not already have an ExternalBuffer subclass, do the following: 1 Add a new subclass to ExternalBuffer. 2 Implement sizeInBytes as a class message in your new subclass. sizeInBytes should return the size of the data structure in bytes. When you send new to your new subclass, sizeInBytes is sent to it and used to allocate the

Visual Smalltalk Enterprise Language Reference 365 CHAPTER 19 OS Interface and API Calls

ByteArray for the contents instance variable. See the implementation of new in ExternalBuffer for an example. 3 Write a method to get and set each field in the structure. ExternalBuffer Messages booleanAtOffset: anInteger Answer the boolean (any non-zero value is true) at anInteger in the receiver. booleanAtOffset: anInteger put: aBoolean Store aBoolean at anInteger in the receiver. Offsets are zero-relative. byteAtOffset: anInteger Answer the byte at anInteger in the receiver. Offsets are zero-relative. byteAtOffset: anInteger put: anObject Store anObject at anInteger in the receiver. Offsets are zero-relative. bytesAtOffset: anInteger count: anInteger2 Answer a ByteArray with anInteger2 bytes copied from the receiver starting at anInteger. Offsets are zero-relative. bytesAtOffset: anInteger put: aByteObject Store aByteObject at anInteger in the receiver. Offsets are zero-relative. handleAtOffset: anInteger (OS/2) Answer the handle (4 bytes) at anInteger in the receiver. Offsets are zero relative. handleAtOffset: anInteger put: anExternalHandle (OS/2) Store anExternalHandle at anInteger in the receiver. Offsets are zero relative. longAtOffset: anInteger (OS/2) Answer the signed double word (32 bits) at anInteger in the receiver. Offsets are zero relative. longAtOffset: anInteger put: anObject (OS/2) Store anObject at anInteger in the receiver. Offsets are zero relative. longAtOffset: anInteger (Windows) Answer the signed double word (32 bits) at anInteger in the receiver. Offsets are zero-relative.

366 Visual Smalltalk Enterprise Language Reference ExternalBuffer and its Subclasses

longAtOffset: anInteger put: anObject (Windows) Store anObject at anInteger in the receiver. Offsets are zero-relative. shortAtOffset: anInteger Answer a signed short integer (16 bits) at anInteger in the receiver. Offsets are zero-relative. shortAtOffset: anInteger put: anInteger2 Store anInteger at anInteger2 in the receiver. Offsets are zero-relative. uLongAtOffset: anInteger Answer the double word (32 bits) at anInteger (an unsigned integer on Windows) in the receiver. Offsets are zero -relative. uLongAtOffset: anInteger put: anObject Store anObject at anInteger in the receiver. Offsets are zero-relative. uShortAtOffset: anInteger Answer the word (16 bits) at anInteger (an unsigned integer on Windows) in the receiver. Offsets are zero relative. uShortAtOffset: anInteger put: anObject Store anObject at anInteger in the receiver. Offsets are zero-relative. ExternalLong A ExternalLong represents a LONG or ULONG, a 32-bit integer. Many APIs take LONG or ULONG parameters or return LONG or ULONG results. Often, a LONG actually contains two 16-bit numbers or a Boolean or a POINT, so class ExternalLong has methods for converting a LONG to some other object and for accessing the two halves. ExternalAddress An ExternalAddress (either ExternalHeapAddress or ExternalGlobalAddress) contains a 32-bit flat address in memory. An ExternalAddress can be used when passing data to the operating system or when the operating system passes the address of a data structure as a parameter in an input message. Usually, passing addresses to the operating system is done by specifying struct for the parameter type when making an API call. This causes the address of the bytes of the object to be passed.

Visual Smalltalk Enterprise Language Reference 367 CHAPTER 19 OS Interface and API Calls

This works because the system uses the pointer during the API call, but not after the call has returned to Visual Smalltalk. (If an API call were to save the address of an object, there would be serious problems, because the object would probably move during the next garbage collect.) Occasionally the operating system does keep the address that is passed as a parameter. In those cases, the object must be copied out of Visual Smalltalk memory. This is done by sending copyToNonSmalltalkMemory: to ExternalAddress which allocates a memory block, copies the object to it, and answers an ExternalAddress containing the address of the memory block. This address can then be passed to an API by sending asParameter to it and using ulong as the parameter type rather than struct. Note that this memory must be explicitly freed by sending the free message to the instance of ExternalAddress when the memory is no longer needed. ExternalSegmentedAddress The ExternalSegmentedAddress class enables you to access the Intel 16:16 segmented addressing mode. ExternalSegmentedAddress is the segmented equivalent of the base class ExternalAddress that deals with the Intel 0:32 flat addressing mode. There are also methods in ExternalAddress that perform conversions between segmented and flat addressing modes. ExternalSegmentedAddress should be used only when passing in ExternalAddress type objects in API calls that expect 16-bit addresses (ulong parameters). The and API directives (c:, pascal:, and api: in a DynamicLinkLibrary16 subclass) will perform the conversions from flat to segmented addresses for the “struct” parameter type. But when you use an ExternalAddress, the “ulong” parameter type is used. Since the parameter is not a “struct”, it will not be automatically converted, so you need to use the new classes and methods. For example, the following piece of code calls an API that returns a 16-bit address (note that the API is described with or ): | address | address := MyDLL someCallToAnswerA16BitAddress. address = 0 ifTrue: [^nil]. ^String fromAddress: ( ExternalSegmentedAddress fromInteger: address ) asFlatAddress

368 Visual Smalltalk Enterprise Language Reference ExternalBuffer and its Subclasses

The API return is compared to zero. If it is nonzero, it is first read as a segmented address by creating a temporary ExternalSegmentedAddress object. Finally, it is converted to a flat address by sending it the message ExternalSegmentedAddress>>asFlatAddress. For example, the following piece of code calls a 16-bit API with a String object that is accessed via a 32-bit flat address. Note that the method example16: is declared as: or ) callExample16: aString | aStringAddress | aStringAddress := ExternalAddress copyToNonSmalltalkMemory: aString. self example16: aStringAddress asSegmentedAddress asParameter The methods in ExternalAddress enable the aStringAddress object to be converted to a segmented address by sending it the message asSegmentedAddress. Remote ExternalBuffers When interfacing with environments other than Visual Smalltalk, you may be given a C pointer to a structure to access the bytes of the structure outside of Visual Smalltalk memory. You see this, for example, when a Windows ‘wm’ message or an OS/2 ‘WM’ message passes a pointer to a structure in one of the message arguments. One way to access the fields of such a structure is to copy the bytes to an instance of ExternalBuffer using fillFromAddress:. If you need to change one of the fields, copy the bytes back to the non-Visual Smalltalk address using copyToAddress:. Visual Smalltalk also allows you to directly access the fields of a structure at its non-Visual Smalltalk address. To do this, an instance of a subclass of ExternalBuffer is still needed, but the contents instance variable contains an instance of ExternalAddress (a pointer to the C structure in non-Visual Smalltalk memory) rather than an object containing a copy of the bytes of the C structure. To create such an object, send the class method atAddress: to the appropriate subclass of ExternalBuffer. This method takes an ExternalAddress object as its argument. and creates an instance of the receiver class, which responds to all the usual access

Visual Smalltalk Enterprise Language Reference 369 CHAPTER 19 OS Interface and API Calls

messages such as longAtOffset: and shortAtOffset:put:. The message returns the value from and stores the value to the non- Smalltalk memory pointed at by the ExternalAddress. Remote ExternalBuffers Example For example, suppose that an ExternalBuffer named SomeUserStructure exists with the following field definitions: field1 ^self uLongAtOffset: 0 field2 ^self uLongAtOffset: 4 Then, we could use the atAddress: method in the following example to access these fields: wmSomeUserMessageWith: wparam with: lparam "Private -- retrieve a value from the structure pointed to by the address in lparam." | address struct value | address := ExternalAddress fromInteger: lparam. struct := SomeUserStructure atAddress: address. value := struct field1. SelfDefinedStructure Whenever you come across a C structure for which there is not already a subclass of ExternalBuffer, you must add one and implement a set-and-get method for each field of the structure. SelfDefinedStructure allows you to have an instance of ExternalBuffer that corresponds to a C structure but does not require an entirely new Smalltalk class. A SelfDefinedStructure will respond to messages for setting and getting the fields of the structure, even though no such methods exist in the image. A generic SelfDefinedStructure definition is defined by sending the message define:withFields: to class SelfDefinedStructure, and passing in the name of the structure and a dictionary that defines the fields of the structure. This is done once, when a project is filed in, for example. An instance of a SelfDefinedStructure is created by sending the message named: to class SelfDefinedStructure, passing in the name of the structure (as defined in define:withFields:). This instance can then be sent messages to get and set the fields of the structure, just as if there were an entire subclass of ExternalBuffer.

370 Visual Smalltalk Enterprise Language Reference ExternalBuffer and its Subclasses

An example of a SelfDefinedStructure is the OPENFILENAME structure that is used to support the FileDialog class. Here's the definition of OPENFILENAME from commdlg.h included with the Microsoft Win32 Software Development Kit for Windows NT. typedef struct tagOFN { DWORD lStructSize; HWND hwndOwner; HANDLE hInstance; LPSTR lpstrFilter; LPSTR lpstrCustomFilter; DWORD nMaxCustFilter; DWORD nFilterIndex; LPSTR lpstrFile; DWORD nMaxFile; LPSTR lpstrFileTitle; DWORD nMaxFileTitle; LPSTR lpstrInitialDir; LPSTR lpstrTitle; DWORD Flags; WORD nFileOffset; WORD nFileExtension; LPSTR lpstrDefExt; DWORD lCustData; BOOL (FAR PASCAL *lpfnHook)(HWND, unsigned, WORD, LONG); LPSTR lpTemplateName; } OPENFILENAME; typedef OPENFILENAME FAR *LPOPENFILENAME; First define the structure with an expression like this one: | d | d := Dictionary new. d at: #lStructSize put: #(0 ulong yourself); at: #hwndOwner put: #(4 handle yourself); at: #hInstance put: #(8 handle yourself); at: #lpstrFilter put: #(12 ulong yourself); at: #lpstrCustomFilter put: #(16 ulong yourself); at: #nMaxCustFilter put: #(20 ulong yourself); at: #nFilterIndex put: #(24 ulong yourself); at: #lpstrFile put: #(28 ulong yourself); at: #nMaxFile put: #(32 ulong yourself); at: #lpstrFileTitle put: #(36 ulong yourself); at: #nMaxFileTitle put: #(40 ulong yourself); at: #lpstrInitialDir put: #(44 ulong yourself); at: #lpstrTitle put: #(48 ulong yourself); at: #flags put: #(52 ulong yourself);

Visual Smalltalk Enterprise Language Reference 371 CHAPTER 19 OS Interface and API Calls

at: #nFileOffset put: #(56 ushort yourself); at: #nFileExtension put: #(58 ushort yourself); at: #lpstrDefExt put: #(60 ulong yourself); at: #lCustData put: #(64 ulong yourself); at: #lpfnHook put: #(68 ulong yourself); at: #lpstrTemplateName put: #(72 ulong yourself); yourself. SelfDefinedStructure define: 'OPENFILENAME' withFields: d. The first at:put: above indicates there is a field named lStructSize at offset 0 that is an unsigned long. When retrieving this field, the value will be sent the message yourself before it is returned. Since a ulong field will always be a Smalltalk integer, yourself simply answers that integer. You would evaluate this expression once and save the image. SelfDefinedStructure has a class variable that keeps all the defined structures. Then, to create an instance of OPENFILENAME structure: openFileName := SelfDefinedStructure named: 'OPENFILENAME'. You can send the following messages to this structure even though there are no methods in the system with these selectors:

Message Description

hInstance Answers an instance handle that has the dialog box template hwndOwner Answers the window that owns the dialog box lpstrFilter Points to a buffer containing pairs of null-terminated filter strings lStructSize Answers the length of the structure in bytes

Note that the implementation of SelfDefinedStructure usually uses the doesNotUnderstand: mechanism of Smalltalk and is therefore slightly slower in accessing fields than using the “traditional” mechanism of creating a subclass of ExternalBuffer with methods for getting and setting the fields. The field accessors for a given SelfDefinedStructure can also be compiled, when performance is critical, by sending the message compileDefinition: to the SelfDefinedStructure class. To remove these compiled methods, send the uncompileDefinition: message. To find out if a given SelfDefinedStructure definition is compiled, send isCompiled: to the SelfDefinedStructure class.

372 Visual Smalltalk Enterprise Language Reference Resources

For SelfDefinedStructure, we are following the naming convention of the structure found in the native environment (i.e., common dialog’s OPENFILENAME structure is named OPENFILENAME in the Visual Smalltalk environment). Resources This section illustrates how you access bitmaps and icons in your program. First of all, resources are objects that an application creates and accesses to present the user interface. GDI resources include bitmaps and icons. A bitmap is an array of bits comprising an image, and an icon is a bitmap that represents an application. Bitmaps are commonly used to create signon screens. Double-clicking on an icon invokes the application. Bitmap Bitmaps may be loaded from a file or from a DLL: • To load a bitmap from a file, use the Bitmap class message fromFile:. The bitmap may be in Windows or OS/2 format, and the file must have a .BMP filename extension. • To load a bitmap from a DLL, use the Bitmap class message fromModule:id:. For an example of creating a resource-only DLL, examine the sample code in the SAMPLE\RESDLL directory. Icon The Icon class gives you the ability to associate a unique icon for each application window, or load icons for display purposes. Programming Interface The following messages illustrate typical operations you perform on icons: ApplicationWindow>>icon: anIcon Set the receiver’s icon. ViewManager>>icon: anIcon Set the receiver’s icon. Icon class >>fromModule: aFileName id: anId Answer an Icon object: aFileName is the filename of a DLL, and anId can be a String or an Integer.

Visual Smalltalk Enterprise Language Reference 373 CHAPTER 19 OS Interface and API Calls

Icon class>>fromFile: fileName Answer an instance of Icon copied from aFileName. aFileName must have an .ICO extension. Icon>>displayAt: aPoint with: aPen Display the receiver through aPen at the given location. Icon>>displayWith: aPen Display the receiver through aPen. Icon>>release Release the receiver’s resources from memory. Examples In this first example, you load the icon from the file TEST.ICO. Note that the file contains a single icon. TopPane new owner:self; icon: (Icon fromFile:'test.ico'); The next example illustrates how you load an icon from a DLL. In this example, you load the icon Disk Browser from the DLL VRESnnW.DLL, where nn represents the release number. TopPane new onwer:self; icon: (Icon fromModule:'VRES30W.DLL' id:'DiskBrowser'); Windows Memory Handles Care must be taken in using Windows memory handles. Some API calls require passing in a global memory handle of a structure. In these cases, first build the structure using a subclass of ExternalBuffer. Add a new ExternalBuffer subclass if the desired structure is not available. Next, convert ExternalBuffer subclass to a memory handle by ExternalAddress memoryHandleFrom: method. Some API calls return a global memory handle as a result. In these cases, first lock the memory handle to obtain a pointer by performing a KernelDLL globalLock: method. Then, copy the contents of the memory pointer to Visual Smalltalk memory by performing ExternalBuffer>>fillFromAddress: method. Finally, unlock and free the memory by performing KernelDLL>>globalUnlock: and KernelDLL>>globalFree:. Care must be taken when allocating, locking, unlocking, or freeing Win32 memory handles. Because of the way Win32 supports moveable memory blocks, a memory pointer is not valid until a

374 Visual Smalltalk Enterprise Language Reference SelfInitializingObject

memory handle has been locked. As soon as the memory handle is unlocked, the memory pointer is invalid. As a general rule, a memory handle should not be locked until the contents of the memory block needs to be accessed, and it should be unlocked as soon as it is no longer needed to be accessed. Also, memory handles should be freed as soon as they are no longer needed. The garbage collector does not automatically free the Windows memory handle, the memory block. Consequently, it is your responsibility to free memory handles by sending release to the object. This applies to all the Windows resources, including font handles, device context handles, brush handles, window handles, bitmap handles, etc. SelfInitializingObject Ordinary Smalltalk objects do not need to be initialized each time Visual Smalltalk is started. They are correctly saved and stored in the image file. However, objects that contain items such as operating system handles do need to be initialized, because the handles are only valid during each Visual Smalltalk session. If your application requires such objects, define them in an uninitialized state whenever the image is saved, then ensure that they are initialized before they are used for the first time. Class SelfInitializingObject makes it easy to initialize an object before it is used for the first time. We recommend you use this mechanism for initializing objects that you would ordinarily think of initializing during startup. Say you have a class variable or a global variable that contains an instance of a DynamicLinkLibrary subclass. Just before image save, the message aboutToSaveImage is sent to the class SelfInitializingObject. You create an instance of SelfInitializingObject and assign it to your variable. This causes your variable to be saved in the image file as an instance of SelfInitializingObject. You create an instance of SelfInitializingObject by sending the message with: aZeroArgumentBlock to SelfInitializingObject. The block that you pass in should initialize your variable to its correct value, and the block should evaluate to the newly initialized object. When the saved image is started, the first time a message is sent to your variable (which is still an instance of SelfInitializingObject), the block you passed in is evaluated. This opens the DLL and assigns the DLL instance to your variable. The system runs normally after that. See the example below.

Visual Smalltalk Enterprise Language Reference 375 CHAPTER 19 OS Interface and API Calls

SelfInitializingObject has one public class method, with:, and one public instance method, isSelfInitializingObject. Any other message sent to an instance of SelfInitializingObject will result in the block being evaluated and the object being initialized: with: aZeroArgumentBlock Answer an instance of the receiver with its initializing block set to aZeroArgumentBlock. The block should initialize a variable if it has not already been initialized. The last expression in the block should be the initialized object. For example: T := SelfInitializingObject with: [T := MyDLL open]. The method isSelfInitializingObject answers true. Thread Support Visual Smalltalk provides support for native OS threads. This support is provided in the form of an easy-to-use mechanism for performing API calls in their own threads. While this does not allow multiple threads to be simultaneously running Smalltalk code it does alieviate the most common problem with multi- threaded systems under Smalltalk: Smalltalk normally blocks during the API call. On OS/2 thread support is implemented using two threads, one to gathersinput and the other to run Smalltalk code. For the most part, this is completely invisible to you. On Windows platforms, thread support is implemented using a single thread. Support is provided in the optional Smalltalk library VNBAPnnp.SLL, and requires VNBAPIp.DLL. The primary interface class in the library is APICall, which is used to represent an API call, either blocking or non-blocking. Instances of this class track the API call as it is underway. The APICall class itself keeps a list of active API calls. Making an API Call There are two ways to make an API call: simple or complex. In the complex scheme, you manually construct the APICall object and provide all of the information needed to describe the call. In the simple scheme, you just send your API message to a different object which does all that for you.

376 Visual Smalltalk Enterprise Language Reference Thread Support

For example, on Windows systems send: KernelLibrary beep: 3000 for: 2000 and on OS/2 systems send: DosLibrary beep: 3000 for: 2000 will beep at 3KHz for 2 seconds. Since by default the call is a blocking call, execution will not proceed past this statement until the 2 seconds have passed. Using the non-blocking support, you may send: api := KernelLibrary nonBlockingInterface beep: 3000 for: 2000 and on OS/2: api := DosLibrary nonBlockingInterface beep: 3000 for: 2000 This makes the API call in its own thread, and the api variable holds the APICall object. You can ask this object: api isRunning to determine if the API call is still running. APICall objects also trigger events when they complete; either the done event for normal completion, or fail for an unsuccessful API call. On Windows you could use these like this: (KernelLibrary nonBlockingInterface beep: 3000 for: 200) when: #done evaluate: [Terminal bell]. and on OS/2: (DosLibrary nonBlockingInterface beep: 3000 for: 200) when: #done evaluate: [Terminal bell]. After the beep this process will ring the bell. In this case, you won’t notice the delay because the rest of Smalltalk keeps going. You may pass any type of argument to an APICall that you would using the standard API interface.

Visual Smalltalk Enterprise Language Reference 377 CHAPTER 19 OS Interface and API Calls

Return Values The APICall interface (both blocking and non-blocking) supports all return types except #double. Configuring Stack Size Threads started using the non-blocking API call support are given a stack of about 20K by default. This can be changed by sending stackSize: to the APICall object before making the call. To do this, you must manually build the APICall object using the to:call: message. Using Non-Smalltalk Memory When making an API call, you may need to copy an object to non-Smalltalk memory (refer to ExternalAddress earlier in this chapter). When making a blocking API call, use an external address to ensure that the location of a buffer passed in the API call remains unchanged after the API returns. For example, you need to copy a buffer to non-Smalltalk memory when you pass the address of a buffer which will hold a needed value after the API function returns. When using non-blocking calls, this is almost always needed to copy objects (at least byte objects) to non-Smalltalk memory, because objects can move in Smalltalk memory even while the call is executing. The system automatically handles all objects that are not #struct (or #self) types. You, however, must explicitly provide buffers outside of Smalltalk’s object space if you pass any of these objects to a non-blocking call. Error Checking The APICall code makes extensive use of exceptions to indicate errors conditions. Several exception classes are defined as subclasses of APICallError. There is currently no support for catching OS exceptions which happen in a non-blocking API call. Calling Conventions The APICall interface only supports standard 32-bit, “C” calling conventions.

378 Visual Smalltalk Enterprise Language Reference Microsoft Windows Message Processing

Microsoft Windows Message Processing Every event received from Windows (the “wm” messages) is sent to the window object that corresponds to the window handle contained in the Windows message. This message is sent while Windows is executing in the WindowProc. Class Window contains a method for each Windows event (they all start with “wm”) that translates the information in the event into an abstract method selector, and causes the more abstract message to be sent to the window. Subclasses of class Window are normally expected to implement these more abstract methods. These abstract messages can either be sent synchronously (directly from the “wm” method) or asynchronously (queue up the message by using sendInputEvent:, which causes the message to be executed after returning from the “wm” method). Most abstract messages are implemented asynchronously. Some messages must be done synchronously, such as the display message sent by the wmPaint:with: method. From time to time, you may need to add a “wm” method to your subclass. Care must be taken when writing one of these “wm” methods. First, the method must return an appropriate value as specified in the Microsoft Win32 Software Development Kit for Windows NT. As a convenience, Visual Smalltalk will take care of calling the default window proc (DefWindowProc) if a “wm” method returns nil. Second, a “wm” method cannot be debugged in the same fashion that other methods can. A WindowProc must return or the entire system hangs. OperatingSystemEvents is a global array that contains selectors for the Windows events that Visual Smalltalk processes. The index into the array is the Windows message number, such as WM_MOUSEMOVE (WmMousemove in OperatingSystemConstants). If there is a Windows event that you want your window to receive, but it is not in OperatingSystemEvents, simply add an appropriate selector at the proper index in the array. If the message number you want to add is greater than the largest index of this array, add your message to the dictionary OperatingSystemEventExtra. Make sure you put a method in class Window before adding to OperatingSystemEvents, because the message will start getting sent as soon as you update OperatingSystemEvents. Also, be sure the selector you add takes two arguments, one for wParam and one for lParam.

Visual Smalltalk Enterprise Language Reference 379 CHAPTER 19 OS Interface and API Calls

Windows Subclassing In Windows application development, subclassing refers to intercepting the messages intended for a window’s DefWndProc, and possibly changing a window or control's behavior before passing the messages on to DefWndProc. Do not confuse this with Smalltalk subclassing. Subclassing, in the Windows sense, allows you to specify special, nondefault, behavior such as event handling. To intercept particular input messages, send the message receiveAllWindowMessages and add the appropriate methods to your subclass of Window. For example, to handle the WM_BUTTON1DOWN message, add a wmButton1Down:with: method. If you answer nil from a “wm” method of a subclassed window, the window’s previous WindowProc is called rather than DefWindowProc (this is what subclassed windows are supposed to do). Note that the window handle must be obtained from Windows, and the subclass message must be sent every time the image is restarted, if you want a window to continue to be subclassed across image save/restart. Windows Message Polling Every well-behaved Windows application must release control to Windows periodically, allowing it to send messages to the running applications. To enforce this good behavior of all Smalltalk processes, the virtual machine will call a system API, called PeekMessage, to check for messages regularly. The frequency of this check can be controlled by using the following method: Notifier setPeekCount: 10000 This method returns the previous setting. The higher the peek count, the longer Windows will go without looking for messages, and the less responsive the user interface becomes. A value of -1 will stop message polling until it is returned to a positive number. A value of 0 resets the count to its initial value. Continuous message polling can have the side effect in some applications of Windows messages being processed by Smalltalk before the application really expects them. Generally, this is not a problem because, for most messages, Smalltalk merely records that they occurred and does most of the processing when the system is free. Only those messages, like WM_PAINT, that require

380 Visual Smalltalk Enterprise Language Reference Microsoft Windows Message Processing

immediate response can be problem. If you think that a section of code should not do any polling, you can use the following method, where the argument is the block of code to execute: Notifier doWithNoMessageProcessing: [a Smalltalk expression] Be very careful when using this method, because absolutely no messages are processed by Windows unless you allow it. Even Ctrl-Break will not work. Interrupts There are times when another module needs to interrupt Visual Smalltalk asynchronously to have it perform a task. When speed is of the essence, sending a Windows message to Visual Smalltalk is not desirable, because it can take a relatively long time to get through to Visual Smalltalk. The user interrupt mechanism described below has been created to solve these types of problems. An API has been added to the virtual machine that allows an interrupt to be placed in the virtual machine's interrupt queue. The API is VOID addInterruptC (U8 nIntNumber) The following code fragment illustrates the setup for and usage of this new API: #include extern VOID addInterruptC (U8 intNumber); . . . VOID CALLBACK TimerProc (HWND hWnd, UINT wMsg, UINT nIDEvent, DWORD dwTime) { addInterruptC (12); KillTimer (NULL, nIDEvent); return 1; } Note that you must link your program with the supplied USERPRIM.LIB. The argument is an interrupt number that you will have previously associated with a selector in the global variable InterruptSelectors. InterruptSelectors is an array with interrupt number as the key and selector as the value. You can inspect this array and use the numbers

Visual Smalltalk Enterprise Language Reference 381 CHAPTER 19 OS Interface and API Calls

that are not currently used. You can also grow the array by hand (i.e., create a larger array, copy the old selectors into it and assign the new array to the global variable). There is no size limit associated with InterruptSelectors. A selector that is assigned to the InterruptSelectors must be implemented as a class method in the Process class. This method can be anything, but it is generally not supposed to take too much time executing. It, or a method it calls, MUST execute the following code before returning to Visual Smalltalk (note that the method is entered with interrupts disabled): Process enableInterrupts: true. The following Smalltalk expression will add an interrupt handler to the InterruptSelectors global array: InterruptSelectors at: 12 put: #testInterrupt. The following class method in Process class will handle the interrupt: Process>>testInterrupt "Implement user interrupt." MessageBox message: 'Timed out'. self enableInterrupts: true. For sample code that demonstrates user interrupts, look in the SAMPLE\USERPRIM subdirectory. The file TEST.SLL contains the Smalltalk code. Make sure you have UPRIM.DLL in your path statement before installting TEST.SLL. OS/2 Message Processing This section covers some more details for those familiar with OS/2 events. Every event received from OS/2 (the WM_messages) is sent to the window object that corresponds to the window handle contained in the OS/2 message. This message is sent while OS/2 is executing in the WindowProc. Class Window contains a method for each OS/2 event (they all start with “wm”) which translates the information in the event into an abstract method selector and causes the more abstract message to be sent to the window. The more abstract method is executed after the WindowProc has returned. Subclasses of class Window are normally expected to implement these more abstract methods. If there is a particular OS/2 event that must be handled during the execution of the WindowProc, then the appropriate wm method can be added to your subclass. However, care must be taken when writing one of these wm methods. First, the method must

382 Visual Smalltalk Enterprise Language Reference OS/2 Message Processing

return an appropriate value as specified in the OS/2 documentation. As a convenience, Visual Smalltalk will take care of calling the default window proc (WinDefWindowProc or WinDefDlgProc) if a wm method returns nil. Second, a wm method cannot be debugged in the same fashion that other Smalltalk methods can. A WindowProc must return or the entire system hangs. OperatingSystemEvents is a global array that contains selectors for the OS/2 events that Smalltalk processes. The index into the array is the OS/2 message number, such as WM_MOUSEMOVE (WmMousemove in OperatingSystemConstants). If there is an OS/2 event that you want your window to receive, but it is not in OperatingSystemEvents, simply add an appropriate selector at the proper index in the array. Make sure you put a method in class Window before adding to OperatingSystemEvents, because the message will start getting sent as soon as you update OperatingSystemEvents. Also be sure the selector you add takes two arguments, one for mp1 and one for mp2. WinSubclassWindow The following describes how to subclass an OS/2 window. Do not confuse this with Smalltalk subclassing. The following assumes you are familiar with WinSubclassWindow and the notion of OS/2 window classes. We use an OS/2 scrollbar window as an example. To subclass an OS/2 window: 1 Get the window’s WindowHandle. This is usually obtained via some WinQuery API call. For a scrollbar, you can use WinWindowFromID or simply send verticalScrollbar to a SubPane to get its vertical scrollbar. 2 Create a Smalltalk subclass of class Window which represents the kind of window you are subclassing. 3 Create a Smalltalk Window object for the window to be subclassed and set its handle instance variable to be the WindowHandle object. For example, | scrollbar wHandle | wHandle := textpane verticalScrollbar handle. scrollbar := Scrollbar new. scrollbar handle: wHandle. 4 Send subclass to the WindowHandle object, as in wHandle subclass. 5 Finally, add the Smalltalk window object to the Notifier, as in Notifier add: scrollbar.

Visual Smalltalk Enterprise Language Reference 383 CHAPTER 19 OS Interface and API Calls

The Smalltalk window object will immediately start getting input messages sent to it just like any other Smalltalk window object. To intercept particular input messages, simply add the appropriate methods to your subclass of Window. For example, to handle WM_BUTTON1DOWN messages, add a wmButton1Down:with: method. If you answer nil from a wm method of an OS/2 subclassed window, the window’s previous WindowProc is called rather than WinDefWindowProc (this is what subclassed windows are supposed to do). Note that the window handle must be obtained from OS/2 and the subclass message sent every time the image is restarted if you want a window to continue to be subclassed across image save/restart. Creating Windows If you call an API that creates a window in OS/2, the call must be made from the input thread rather than the Smalltalk thread. This is because OS/2 delivers input to a window in the thread that created the window. To do this, his is accomplished by sending a special message to the input thread via WinSendMsg. For an example, see CreateMenu: in PMWindowLibraryDLL. Again, this should be completely invisible to you, unless you actually write an API call in a subclass of DynamicLinkLibrary that creates a window. The APIs we know of that create windows are already in PMWindowLibraryDLL, WinCreateStdWindow, WinCreateWindow, WinCreateMenu, WinCreateDlg, WinMessageBox. Primitive Methods Computing is done in a Smalltalk system by objects sending messages to each other. The “real” work, however, is performed in primitive methods. Primitive methods perform low-level functions such as arithmetic operations, indexed instances variable access, and device access. They are also used for higher-level but performance-critical methods such as stream access and block transfers. Primitive methods are identified with an integer primitive number enclosed in brackets following the message pattern. For example, the implementation of the subscripting method at: in class Object is as follows:

384 Visual Smalltalk Enterprise Language Reference Primitive Methods

at. index ^self primitiveFailed Primitive methods have two parts (1) an assembly language part and (2) a Smalltalk part. The assembly language part is identified by the number following primitive: in angle brackets. The Smalltalk part follows the angle brackets. The assembly language part of a primitive is executed first. It concludes by either succeeding (returning an object that is the method result) or failing. If the assembly language part fails, the Smalltalk part is executed to retum the method result. This shared responsibility works efficiently because the assembly language code handles the common but simple cases. Since Smalltalk is much easier to write than assembly language, the Smalltalk code handles the infrequent but complex cases. Primitive Failure Handling Support is provided to enable primitive failure code to obtain information about the reason for an API call primitive failure. The message apiFailureReason can be sent to self in the primitive failure code of an API call primitive method in a DLL class to obtain the primitive failure reason. The API primitive failure codes that can be returned from a DLL API call are:

Code value Code meaning 3 bad DLL handle 4 entry point not found 8 argument error greater or equal to HRESULT error code (result type hresult only) 16r80000000

The primitive failure information is incorporated in the standard DLL primitive failure service invalidArgument. For an API primitive with return type hresult, the primitive failure reason can be any of the preceding or an HRESULT value returned from the callee with the high-order bit set, indicating a failure code return value.

Visual Smalltalk Enterprise Language Reference 385 CHAPTER 19 OS Interface and API Calls

User-Defined Primitive Methods User primitives used to be the only method for a Smalltalk program to access more efficient, external routines written in assembler or a compiled language. When the operating system began providing access to DLLs through API calls, the need for user primitives in Visual Smalltalk was virtually eliminated. There remain a few cases, however, where user primitives provide additional value. For example, if a Visual Smalltalk program loops on the elements of an array, making a separate API call on each loop, calling a single primitive method that loops on that array object directly may be more efficient. User primitives in Visual Smalltalk are implemented as DLL routines. These routines can be written in any language that can be compiled into a DLL, providing the necessary callable entry points. User primitive DLLs are accessed using the API calling methods described earlier in this chapter, under Dynamic Link Libraries and API Calls. You define a subclass of DynamicLinkLibrary representing the DLL, and provide API accessor methods. The difference is that a primitive method takes advantage of the way Visual Smalltalk structures its objects, so that it can access objects directly using object pointers. Several sample files are provided in the EXAMPLES\USERPRIM directory that simplify accessing objects. The example program UPRIM.C contains user primitive functions that demonstrate how to use the definitions in OBJECT.H to operate on objects. User primitive methods should always be kept short, direct, and used only when necessary. Object Pointers Visual Smalltalk uses 32-bit memory addresses as object pointers. A pointer with the low bit turned on indicate that it is a pointer to a SmallInteger rather than a memory pointer. The remaining 31 bits of a SmallInteger contain its sign and magnitude. All other pointers are the direct memory address of the object. The file OBJECT.H defines macros that identify SmallInteger objects and that convert between C integers and SmallIntegers. The objects nil, true, and false have fixed addresses. The C compiler and linker resolve these values using the information provided in FIXDPTRS.H.

386 Visual Smalltalk Enterprise Language Reference Primitive Methods

Character objects also reside at fixed locations. The mutate( ) (Windows) and Mutate( ) (OS/2) examples in UPRIM.C demonstrates how to access these objects.

NOTE: Special care must be taken when writing primitives in the Win32s environment. Upon entry to a user primitive an instance of a UPRIM_IF structure must be initialized to correspond to the calling instance of the virtual machine. This structure MUST NOT BE of a static or global storage class. A macro, InitializeIF, is provided to initialize an instance of this structure. Examine the sample code for usage examples.

Accessing Objects within Primitives Objects consist of a number of 32-bit words of header data and a number of words of instance data. An object pointer points directly at the first instance variable of the object. Instance variables of an object are all the same size. Objects containing object pointers have 32-bit instance variables; all other have eight-bit instance variables. The order of the instance variables in an object is the order in which the variables are defined by the class of the object, including inherited instance variables, which come first in the list in the order of definition in the hierarchy. Normal C array subscripting may be used to get and set the values of instance data. The header of an object is at a negative offset from the object pointer and contains the size of the object, an indication of its class, and various flags. The accessing macros and routines provided in OBJECT.H simplify getting the necessary information about an object. It is necessary to inform the garbage collector of stores of objects into objects, to ensure proper operation of the runtine system. Use the uPrimIF.GCUpdate ( ) function to notify the garbage collector, as illustrated in the Mutate( ) example code. The garbage collector does not need to be updated if a small integer is stored. Returning from a User Primitive User primitive failure code, which follows the API call in the API accessor method, is only executed if the call to the DLL could not be resolved. User written primitives should return a value indicating success or failure. This allows Visual Smalltalk to distinguish an inability to access the support DLL from a primitive failure caused by reasons known only to the primitive.

Visual Smalltalk Enterprise Language Reference 387 CHAPTER 19 OS Interface and API Calls

By good programming practice, a primitive that fails should not modify the state of the computation. Therefore, your primitive should perform all checking before storing to memory, or else be able to undo such stores if the primitive fails. Generating Smalltalk Interrupts within Primitives On Windows platforms DLL routines may inform Visual Smalltalk of an event which has occurred by posting an interrupt. An interrupt is created by calling the function UPrimIF.AddInterrupt( ) from within a user primitive, with the appropriate interrupt number as an argument. The Process class then decides how to handle the interrupt. The number of the generated interrupt is used as an index into the InterruptSelectors global variable array, and the selector (a symbol) at that index defines a message which is sent to the Process class. Install TEST.ST for an example of handling interrupts. Memory Access and User Primitives Smalltalk methods cannot corrupt object memory because an object is not allowed to access memory outside itself. Primitive methods, on the other hand, can access all of object memory and, therefore, have the opportunity to corrupt object memory. The implementor of a primitive has the responsibility to guarantee that only the instance variables of the receiver object are changed. If you have been using (debugging) a primitive that may have stored erroneously in memory, discard the image. Macros and Functions The file OBJECT.H contains a number of C macros and procedures for working with objects within a user primitive method. USERPRIM.LIB is provided for linking your DLL if you use any of the procedures declared in OBJECT.H. In these functions and macros, “oop” is an object pointer.H. Functions void GCUpdate( OOP lOop, OOP rOop ) The GCUpdate( ) function should be called after rOop is stored into lOop.

388 Visual Smalltalk Enterprise Language Reference Primitive Methods void addInterruptC( U8 interruptNumber ) void AddInterrupt( U8 interruptNumber ) The addInterruptC( ) (Windows) and AddInterrupt( ) (OS/2) functions add an interrupt with the specified number (an index into the InterruptSelectors array) to the Visual Smalltalk interrupt queue. Macros InitializeIF( pIf , pResult ) (Windows only) Initializes the UPRIM_IF structure, for Win32s support. isSmallInteger( oop ) Answers nonzero if oop is a small integer. asSmallInteger( cInt ) Transform a C integer into a small integer. fromSmallInteger( smallInt ) Transform small integer into a C integer. asPHeader( oop ) Transform oop into a pointer to its header. objectClass( oop ) Answer the class for the given object pointer. objectSize( oop ) Answer the number of bytes or slots in an object. isBytes( oop ) isPointers( oop ) notIndexed( oop ) isIndexed( oop ) hasNullTerm( oop ) Answer nonzero if object size includes a null terminator. hasNamedInstanceVars( oop ) Answers nonzero if the object has named instance variables. numberNamed( pIf , oop ) Answers the number of named instance variables.

Visual Smalltalk Enterprise Language Reference 389 CHAPTER 19 OS Interface and API Calls Protection Violation Handling Protection violations, such as accessing memory at an illegal address, generally cause the currently running application to “crash”. Visual Smalltalk recognizes when protection violations occur. If protection violations occur during an API call or user- defined primitive, Visual Smalltalk attempts to bring up a walkback and keep the image running. This usually works, depending on the state of the system when the violation occurred. The walkback is titled Visual Smalltalk Protection Violation and is like any other walkback. That is, it contains a stack trace of the calls leading up to the violation, allowing the user to inspect the variables used when making the call. When an exception is not recoverable (for example, the exception did not occur with an API call), Visual Smalltalk attempts to log information that will aid in identifying the source of the problem in the ERROR.LOG file.

390 Visual Smalltalk Enterprise Language Reference CHAPTER 20 OLE Support Overview Visual Smalltalk supports the major features of OLE version 2, including the underlying support for accessing objects implemented according to the Common Object Model (COM). In this release, Visual Smalltalk provides: • Basic COM functionality, including interface function callout and callin, OLE structured storage technology, clipboard and drag/drop data transfer, and moniker support • Container application support, allowing Smalltalk applications contain linked and embedded OLE objects with in-place activation • Ability to use OLE custom controls (OCX) in a Smalltalk application • An OLE Control wrapper part for including OLE custom controls in an application built in the workbench • OLE Automation events are fully supported The OLE Control wrapper part is described in the Visual Smalltalk Enterprise Part Reference. This section focuses on using OLE support from Smalltalk. OLE Applications OLE applications are either clients or servers of OLE objects. OLE server applications create and maintain objects. OLE container applications are consumers of these objects, which can be used as embedded or linked objects in a container. OLE container applications create and manage compound documents. These are documents which seamlessly incorporate data, or objects, of different formats. Sound clips, spreadsheets, text, and bitmaps, for example, are objects commonly found in compound documents, and often referred to as compound document objects.

Visual Smalltalk Enterprise Language Reference 391 CHAPTER 20 OLE Support

Each compound document object is created and maintained by its server application, but through the use of OLE and its in-place activation and uniform drag/drop transfer capability, the services of the different server applications are integrated. OLE Container Support Visual Smalltalk provides the support necessary to build a pure OLE container application. Such an application can hold and interact with linked and embedded OLE objects. Structure of a Container Application As with all Visual Smalltalk windowing application, the top level window is an instance of TopPane, and each pane in the window is an instance of some subclass of SubPane. For a container application, at least one subpane will be an instance of OLEClientSitePane. The top pane serves as the OLE container, and has associated with it an instance of OLEContainerObject. The container object handles responsibilities such as providing shared access to the window. The OLEContainerObject has one or more instances of OLEClientSiteObject associated with it. An instance of OLEClientSiteObject is the only object that directly interfaces to the OLE object contained in the application. Each client site object is associated with an instance of OLEClientSitePane, which displays the visual rendering of the contained object.

Window TopPane

OLEContainerObject

OLE Objec t OLEClientSitePane

OLEClientSiteObject

392 Visual Smalltalk Enterprise Language Reference OLE Container Support

The client site object stores information about the OLE object stored in it, including the identity of the object occupying the client site, the interfaces it supports, and much more. An OLE client site can contain an OLE object as either an embedded object, which stores its data in the container’s compound document file, or as a linked object, which is a reference to a separate file which contains the object’s data. There are standard user interface facilities, common to all OLE container applications, which allow users to create and manage the embedded and linked objects in the application. In-place activation provides seamless integration for the user when editing compound document objects. When you create a client site in a container, you can obtain the client site object associated with the OLEClientSitePane by sending the message siteObject to the client site pane. Similarly, the pane in which the compound document is rendered in the application can be obtained from the site object by sending it the message sitePane. The container object associated with your application can be obtained by sending the message container to the application coordinator or to any client site that you have created in the view. An OLE container object provides a number of services that allow you to manage the compound document storage associated with the container. The Container Application Framework To simplify building container applications, Visual Smalltalk provides a framework within the Application Coordinator framework. This framework does much of the work of building a container application, including connecting a client site pane with a container and adding a menu with the necessary document control dialogs. The protocol provided by OLEContainerCoordinator allows an application to create and manage menu items for object verbs, so that when an object in a client site pane is selected, the object menu has the correct label and verbs. Standard services include menu items that provide easy access to OLE user interface facilities, such as the Insert Object, Edit Links, and Paste Special dialogs. OLEContainerCoordinator extends the window construction protocol of its superclass, ApplicationCoordinator, with protocol to create a properly initialized OLEClientSitePane and to enable OLE drag-drop.

Visual Smalltalk Enterprise Language Reference 393 CHAPTER 20 OLE Support

Most OLE applications are created as subclasses of OLEContainerApplication, which is a subclass of OLEContainerCoordinator. OLEContainerApplication provides services that define standard operations usually found on the File, Edit, and Insert menus of OLE applications. Building a Container Application You will typically build a container application as a subclass of OLEContainerApplication, which is itself a subclass of OLEContainerCoordinator. This approach is illustrated in the sample container application. As always, when you create a subclass of Application- Coordinator, you create a view, define the menus, and configure events that drive the application logic based on user interaction. When you create an OLE container applicant, you also need to provide a compound document file for the backing store of the container. The class OLECompoundFile provides services for creating and accessing the OLE compound file that you use in your container application. (Refer to OLE Structured Storage Support later in this chapter.) When you build the view for the application, you add a client site pane using the message: createSitePaneIn: aWindow for: aContainerCoordinator name: aClientSiteName framing: aFramingBlock This message adds the client site pane to the view you are constructing You must also assign a unique name to each OLE client site in the container. The easiest way to do this is to allow the container to generate a name for the site. The container framework creates an instance of OLEContainerObject when the view is constructed, and stores it in the container instance variable. To get a name for the client site, send getNextSiteName to the container: aContainerCoordinator container getNextSiteName Since the container can have multiple sites, this method generates a unique name for each client site. When the user selects an OLE object in the container, it becomes the active site in the window. As usual, the menu commands operate on the currently active site. The framework keeps track of the currently active site in the activeSite instance variable.

394 Visual Smalltalk Enterprise Language Reference OLE Container Support

OLEContainerCoordinator provides services to support all the standard menu commands for an OLE container. OLEContainer- Application defines the standard menus for an OLE container in the application. The additional menus are: • Paste Special... • Insert Object... • Links... • Object •Edit • Open By default, these are added to the Edit menu. Standard dialogs are provided to support Paste Special, Insert Object, and Links menu items. The Object menu items invoke the appropriate operations from the OLE object’s server. The standard OLE container dialogs are supported by in these classes: • OLEBusyDialog • OLEChangeIconDialog • OLEConvertDialog • OLEEditLinksDialog • OLEInsertObjectDialog • OLEPasteSpecialDialog To provide a title for your application window, the framework uses the return value of the containerName method. Reimplement this method to return an appropriate title string. You must also provide error handling for OLE operations when you create an OLE container application. As discussed in more detail in Error Handling below, most OLE operations can cause exceptions to be signalled. To provide error handling, you need to handle the OLEError exception. For an example of an OLE container application, install OLE Container Sample using the Service Manager.

Visual Smalltalk Enterprise Language Reference 395 CHAPTER 20 OLE Support OLE Control Support You can use OLE custom controls in your application by adding an OLE control pane to the application view, just like you add other visual controls. Because an OLE control is a special kind of an OLE object, you can most easily use OLE controls when you implement your application as a subclass of OLEContainerCoordinator. A part is provided in the workbench for including OLE controls in your application windows. This is the easiest way to use OLE controls in your application, and should be used whenever possible. Using OLE Controls When you build the view for the application, you add an OLE control by using the message: createControlSitePaneIn: aWindow for: aContainerCoordinator name: aSiteName framing: aSizeSpecification This message adds an OLEControlSitePane to the view that you are creating. An OLEControlSiteObject is associated with the control site pane to provide the connection between your application and the OLE control. As with client sites in a container, you must assign a unique name to the control site. The easiest way to do this is to send the getNextSiteName to the container object associated with your view to cause a unique name to be generated. To specify the control that is to be used, you must set the OLE object class ID (CLSID) of the control site pane by sending the message clsid: with the CLSID of the control. The OLE control site handles creating an instance of the OLE control in your application and providing the connections which allow you to interact with the control through the methods, properties, and events that it supports. The OLE control site pane allows you to invoke the methods (functions) which constitute the behavior of the control, as well as to get and set the values of the properties that the control supports. The messages supported by the OLE control pane to provide access to the methods and properties of the control can be determined by sending the controlMethodSelectors, controlPropertyGetSelectors, and

396 Visual Smalltalk Enterprise Language Reference OLE Control Support controlPropertySetSelectors messages. The names of the supported properties of the control can be obtained by sending the message controlProperties to either the OLE control pane or the control object associated with it. In addition to the specific messages for individual functions and properties, a generic invocation protocol is provided by the control pane to provide functionality equivalent to the general evaluation protocol supported by messages and other evaluable actions. To invoke a function or access a property value of the control, you use the messages: invokeMethod: aSelector withArguments: argValuesArray Invoke the control method named aSelector with the arguments in argValuesArray. Answer the result value (nil if none). getProperty: propertyName Answer the value of the property named propertyName. getProperty: propertyName withArguments: argValuesArray Answer the value of the control’s property named propertyName. argValuesArray is the Array of argument values for a parameterized property. It may be zero length for unindexed properties. “ setProperty: propertyName value: newValue Set the value of the property named propertyName to the newValue. setProperty: propertyName withArguments: argValuesArray Set the value of the control’s property named propertyName to the last element of argValuesArray. argValuesArray is an Array of values for an indexed property. It may contain only one element, the new value, for unindexed properties. The events supported by the control are triggered by the OLE control site pane, allowing you to configure event handlers for the OLE control in the usual fashion. Use the standard events aboutToChangeProperty: and changedProperty: to notify clients about changes in the properties of the control. The aboutToChangeProperty: event can be vetoed by sending the message abortChange to the OLE control pane, which notifies the control that the property change should not be made. The event changedProperty: is triggered after the control property has changed. Both of the standard property-change events provide the name of the property as the event argument value.

Visual Smalltalk Enterprise Language Reference 397 CHAPTER 20 OLE Support

For an example of an OLE control container application, install the OLE Control Sample using the Service Manager. The control sample is a generic control container which allows you to install various controls and examine the supported protocol for methods, properties, and events. Using OLE Controls in Other Frameworks You can use an OLE control in a view constructed by any ApplicationCoordinator or ViewManager class, not just an OLEContainerCoordinator subclass. However, if you use a control in an application other than as an OLEContainerCoordinator subclass, you need to replicate the logic that attaches a container object to the application view, and that correctly creates and installs a control site in the container. You can find this logic in the OLEContainerCoordinator class methods which create the view and the control site pane, as well as the methods in that class that are invoked to support these two operations. You will also need to provide a backing storage that the controls in your view can use to manage their object state while your application is executing. One way to do this is to associate a temporary backing file with the application’s container by sending the message newDocumentFile to the container object. Sources for OLE Controls OLE controls can be obtained from many vendors. In order to use an OLE control, you will usually need to refer to the OCX vendor’s documentation for information on how to install the control, any configuration requirements for using the control, and for information about the capabilities of the control. The OCX vendor must provide you with information describing the specific methods, properties, and events supported by the control. OLE Client Site Object Interfaces As mentioned earlier, an OLEClientSiteObject instance is the only object that directly interfaces with an OLE object. The client site object both provides services to and can request services from the OLE object it contains, using methods defined in the class. An OLE object in a container is associated with what is referred to as a client site in the container. A client site manages the interaction between the container and a single contained object. The compound document object can be either an embedded or linked OLE object.

398 Visual Smalltalk Enterprise Language Reference OLE Control Support

The OLEClientSitePane is a window that provides client site capabilities in a container application window. The OLEClientSiteObject provide the functionality for directly interacting with the OLE object in the OLEClientSitePane. The OLEClientSiteObject implements important functions such as those which create, activate, and release OLE objects. It also implements save and restore functions to and from the compound document storage. The OLEContainerCoordinator provides a protocol for invoking these functions from the application’s standard menu operations. OLEClientSiteObject implements the following interface functions to interact with the contained object: • IOleClientSite • IAdviseSink or IAdviseSink2 • IOleInPlaceSite If the container does not allow linking to its contained objects, IAdviseSink2 is not implemented. The IOleClientSite interface is the primary interface by which a container provides services to the object. The container provide one instance of IOleClientSite for every compound document object it contains. The IAdviseSink interface supports the flow of notifications between the object and the container. The container uses IAdviseSink to receive asynchronous notifications. There are three types of asynchronous notifications: compound document, data change, and view change. These notifications may be used to trigger events in Smalltalk. The IOleInPlaceSite interface is used by object server applications to interact with the object in the client site window to provide in-place activation. OLE Container Object Interfaces OLEContainerObject implements the functionality for creating and managing compound documents, and defines a protocol for specifying client sites and managing the name space for contained objects. OLEContainerObject implements the following interface functions: • IOleContainer • IOleInPlaceFrame • IOleInPlaceUIWindow

Visual Smalltalk Enterprise Language Reference 399 CHAPTER 20 OLE Support

If the container does not allow linking to its contained object, IOleContainer is not implemented. The IOleInPlaceFrame interface is used by object applications to control the display and placement of the composite menu, keystroke accelerator translation, context-sensitive help mode, and modeless dialog boxes. The IOleInPlaceUIWindow interface is used by object applications to negotiate border space on the container frame window. An OLEContainerObject also uses the following interfaces: • IStorage • IMoniker The IStorage interface provides structured storage for the compound document created and managed by the container. The IMoniker interface provides a moniker for the compound document file. Creating an OLE Application An OLE application is an application that employs OLE objects in defining its operation. OLE objects provide services to clients by supporting interfaces, sets of functions that a client application can call to perform whatever processing the object supports. Visual Smalltalk provides the mechanisms necessary to access external OLE objects and invoke their processing in support of an interface. You can also, and often must, implement an OLE object in Visual Smalltalk, and make its interfaces available to the external clients. Acquiring OLE Objects In the simplest case, a Smalltalk OLE application is a client of an external OLE object. External OLE objects occupy their own memory space, and you gain the use of it by establishing a connection with one or more of its interfaces. The actual connecting work is done by underlying OLE mechanisms built into OLE, but you need to be able to identify an object and request one of its interfaces.

400 Visual Smalltalk Enterprise Language Reference Creating an OLE Application

To use an OLE object in an application, you create a new instance of the object and send messages to it, as usual for Smalltalk objects. The public Smalltalk interface implemented for the object manages the intricacies of invoking the interface functions directly. Basic OLE Interface Support The most important aspect of OLE is the interface, which provides the connection between an OLE object and its clients. An interface is simply a collection of related functions, representing a well-defined contract between an object and its clients. The interface definition specifies the syntax and semantics of each function in the interface. An OLE object typically supports several interfaces that together represent the services provided by the object. In Visual Smalltalk, interfaces are represented by subclasses of the OLEInterface abstract superclass. Since all OLE objects support the IUnknown interface, it is implemented by the IUnknown class under OLEInterface. All other interfaces are implemented as subclasses of IUnknown. Acquiring OLE Interfaces OLE objects implement specific behavior for the functions supported by their interfaces. To acquire a specific interface from an OLE object, you must first have a pointer to some interface supported by the object supporting that interface. From this interface you can then get pointers to additional interfaces supported by the object. If your application is a container application, you can acquire interfaces from any object instance in a container site. For other OLE applications, you need to create an instance of an OLE object that you know is installed on your system and listed in the system registration database. You instantiate an OLE object by calling either OLE interface functions or API’s. In Smalltalk, a few OLE interfaces have class methods to create new OLE object instances. For example, the IMoniker interface class provides services for creating new instances of standard types of OLE moniker objects and returning an IMoniker interface instance on the newly created moniker. A more general mechanism for instantiating an OLE object is to use the object creation services provided by the IClassFactory interface class. The createInstance:iid: message instantiates an OLE object of the specified CLSID, and returns the specified

Visual Smalltalk Enterprise Language Reference 401 CHAPTER 20 OLE Support

interface from the newly created OLE object. Since all OLE objects implement IUnknown, you typically ask for that interface first. The createInstance: message can be used in this case. For example, to create a new instance of some OLE class and obtain its IUnknown interface, evaluate an expression of the form: anIUnknown := IClassFactory createInstance: clsid. where clsid is the class ID for the OLE class. Once you have a reference to one of an object’s interfaces, you can acquire additional interfaces by sending queryInterface: to already known interface. For example, having anIUnknown as above, we can acquire a reference to the object’s IDataObject interface, if it supports this interface, by sending: anIDataObject := anIUnknown queryInterface: IID_IDataObject To create an inner object, for use within an aggregate object, you must specify the controlling unknown of the aggregate when instantiating the inner object. For example: anInnerUnknown := IClassFactory createInstance: clsid iid: IID_IUnknown controllingUnknown: self controllingUnknown. If you need to create several instances of the class, you can obtain an instance of the class factory for the OLE object class by sending the message forCLSID: to IClassFactory. Once you have the class factory itself, you can create any number of objects. For example, to create two instances of some OLE object, you could evaluate an expression such as the following: aClassFactory := IClassFactory forCLSID: clsid. "Create and get IUnknown" anUnknown := aClassFactory createInstance. "Create and get IID_X" anIDataObject := aClassFactory createInstance: IID_IDataObject. aClassFactory release. Managing Object References OLE interface reference counting is the mechanism in OLE for managing in a system of cooperating software components. Briefly, the reference count mechanism is used to keep track of how many clients are using an interface, and

402 Visual Smalltalk Enterprise Language Reference Creating an OLE Application ultimately its underlying OLE object. The object continues to provide services as long as any client is using at least one of its interfaces. When a client acquires an interface, the reference count of that interface is incremented. When the client is done using the interface, it is responsible for releasing the interface by sending the release message. Releasing the interface decrements its reference count and allows the object to determine whether its services are still required. When an object no longer has any clients, it can terminate itself, releasing any interfaces it has acquired. The period between when a client obtains an interface and when it releases the interface constitutes the lifetime of the client’s ownership of that interface. During this lifetime the client, or any object with which the client shares the interface, can freely invoke any function in that interface. The COM specification defines several rules for reference counting, with which you should be familiar. The rules are fairly simple for client applications, and for a Visual Smalltalk application amount to requirements for releasing interfaces and for making separately countable references to interfaces. In the simplest case, an application will acquire a single reference to an interface, by sending queryInterface: or a similar messages. While in possession of the interface, the application can invoke any function supported by the interface. When finished using the interface, perhaps as part of the application shutdown processing, it will release the interface by sending release to the interface. Usage is not always this simple, however, and may require several references to an interface. Smalltalk applications involve many objects with varying lifetimes. Any object can acquire an interface reference and, since the interface is represented by a Smalltalk object, can be shared with any other object. Your responsibility as a programmer is to make sure that objects have separate references to a shared interface when necessary. release Objec t A

Objec t B

Visual Smalltalk Enterprise Language Reference 403 CHAPTER 20 OLE Support

Any time your application gets a new interface reference by making an API or a function call to an OLE object, it receives a new, separately counted reference. Your object is responsible for ensuring that the interface is released. Note that because the reference is represented in Visual Smalltalk as a Smalltalk object, that is as an instance of a OLEInterface subclass, it can be shared by any number of other Smalltalk objects. This is where some care must be taken. In general, your object can use the interface reference as an argument to any function call (message send) since the receiver will only have the reference for the duration of the function call. Since the lifetime of the function call is completely contained within the life time of the sender, the sender and receiver objects can use the same copy of the interface, and the sender retains control of the lifetime of the reference. Cooperating objects within your application can also share a reference to an interface that one of your application objects has acquired. An interface reference can be freely shared with other objects in your application, as long as the object that acquired the interface can ensure that no other object is still using the interface when it is ready to release it. In some cases, it is not possible for a cooperating object to assure the original owner that it will be done using the interface when the owner is ready to release the interface. In this situation, a separate copy of the interface should be made using the separateReference message. This creates a separate reference to the interface that can be used independently by the cooperating object. Each of your application objects can now use the interface independently and release it when they are done. The original owner releases the original interface reference when it is done using it, as usual, while the cooperating object is responsible for releasing its separate reference to the interface when it is done. separateReference release Objec t A

release Objec t B

404 Visual Smalltalk Enterprise Language Reference Creating an OLE Application

Using OLE Interface Functions An OLE object invokes the functions of its OLE interfaces by sending messages to an instance of the relevant OLEInterface subclass. Subclasses of OLEInterface define each OLE interface known to Visual Smalltalk. Subclasses of OLEInterface are named with the common name of the interface, e.g., IUnknown, or IDataObject. The interface represented by a class is identified by its unique IID (interface identifier), which can be obtained by sending the iid message. The IID of an interface instance can also be obtained by sending the iid message to the instance. Interface IID values are also defined in the OLEConstants pool. OLEInterface subclasses present the public interface to OLE interfaces and their functions. The public interface includes a message for every function defined in the OLE interface. The class may also implement methods to simplify common usage patterns. The interface function methods in an OLEInterface class handle the details of invoking the native host-level interface and API functions. Where necessary, transformations are provided between Smalltalk values and the host data type values used to directly invoke the native host function. This encapsulation of the host data type management within the interface class allows you to invoke OLE interface functions in a natural fashion in your Smalltalk application, with normal Smalltalk objects provided as arguments to the interface function message and returned as the message result value. Error Handling When you design an OLE application, as with any application, it is your responsibility to provide suitable error handling. Almost all OLE interface functions and API's can cause the OLEError exception to be signalled to indicate failure conditions. You must decide how to handle such error conditions in your application. Using the standard facilities of the Smalltalk exception system, you have great flexibility in determining how to implement error handling and where in your application to locate the logic to handle exception conditions resulting from function failures. Almost all OLE interface functions return a status code indicating success or failure as the function value. In Smalltalk, an error result from an interface function results in an instance of the error exception OLEError being signalled. An OLEError includes the

Visual Smalltalk Enterprise Language Reference 405 CHAPTER 20 OLE Support

HRESULT return code, as well as a message describing the error. Processing of the interface function is terminated when an error is signalled. In a small number of cases, an OLE error code returned by an interface function is considered to be a “normal” return code and not signalled as an error. For example, the Smalltalk binding of the IUnknown::QueryInterface function treats the E_NOINTERFACE error code as a reasonable return condition, for which nil is returned, with no error signalled. Some interface functions return a status code indicating that the function succeeded, but which provide additional information. For example, the IStorage::CreateStorage function returns STG_S_CONVERTED when the existing storage of the same name was replaced with a new storage containing the single stream CONTENTS. In Smalltalk, a success result other than S_OK from an interface function is indicated by signalling an instance of OLEResultNotification. An OLEResultNotification includes the HRESULT return code, as well as a message describing the result code. Clients can use the Smalltalk exception handling system to detect such success notifications if this is of interest. Processing proceeds normally after the notification is signalled, independent of whether a client exception handler has been provided. Managing Memory An OLE application must follow certain memory management rules whenever an allocated block of memory is passed as an argument to an interface function or an OLE API. When you call an OLE function that returns the address of a value, such as a structure or a string which the callee allocated to service your request, you must release the memory when you are done with the data by sending the release message. OLE interface functions and API calls classify parameters into one of three groups: in, out, and in/out. An in parameter is allocated and freed by the caller. Since ownership of the memory is not transferred, an in parameter can be allocated in whatever fashion is preferred by the caller. Out and in/out parameters that contain pointers to memory, on the other hand, represent memory whose ownership is transferred, and so must be allocated using the OLE task allocator. An out parameter is allocated by the callee then transferred to the caller, so must be released by the caller. An in/out parameter is allocated and eventually freed by the caller, but, the callee may

406 Visual Smalltalk Enterprise Language Reference Implementing OLE Objects

free and reallocate the memory as necessary. Since ownership of the memory is transferred, in/out and out parameters must be allocated and released using the OLE task allocator. A Smalltalk OLE application is responsible for releasing any memory it obtains as a return value from an interface function, when it is done using that memory. This situation usually occurs when a data structure or string is allocated in external memory by an interface or API function that you call. You release the memory by sending it the message release. In most cases, the actual OLE memory address is returned as a Smalltalk object, such as an ExternalBuffer data structure class. Sending release will ensure that any memory that was allocated is properly released when you are done with the data that was returned from the OLE function.

NOTE: In the current release, string return values are generally brought into Smalltalk memory as a side effect of converting the Unicode string encoding returned by OLE functions into a Smalltalk string. In this case, the memory containing the returned string is released before returning the string to the Smalltalk caller. Although not required at this time, we recommend that you release string return values, since this behavior is not guaranteed in the future.

Implementing OLE Objects OLE applications are not usually pure client applications, but must themselves present an interface to a serving object. To do this, the application must implement one or more OLE objects in Smalltalk giving access to interfaces for use by the external object. Implementing an object in Visual Smalltalk involves creating a subclass of the abstract superclass OLEObject, specifying the set of interfaces supported by the object, and creating methods to implement the interface functions that your object supports. OLE objects are represented in Visual Smalltalk as subclasses of OLEObject. An OLE object is associated with one or more interfaces, and implements methods that access the functions in those interfaces and maintain its internal state. Supporting OLE Interfaces The capabilities of an OLE object are determined by the interfaces which it exposes to clients and by the implementation of the interface functions that it performs when an client invokes an

Visual Smalltalk Enterprise Language Reference 407 CHAPTER 20 OLE Support

interface function. Specifying the interfaces which are supported by the object and implementing the interface function processing is the main activity in an OLEObject subclass. Every OLE object supports the IUnknown interface, which is created when the object is instantiated. Additional interfaces supported by the object determine its personality and behavior. An OLE object must be able to return each of its supported interfaces when requested by a client through invocation of the IUnknown::QueryInterface function. The OLEObject framework class provides a standard implementation of the QueryInterface function which correctly handles requests for the IUnknown interface, which is allocated and managed by the superclass. Each subclass is responsible for providing storage for its other supported interfaces, such as by allocating an instance variable for each supported interface, and for reimplementing the method getInterfaceForIID: to handle requests for any interfaces other than IUnknown. The method should return the requested interface, if it is supported, or nil if it is not a supported interface. The implementor of an OLE object chooses whether to create all its supported interfaces at once, when the object is created, or implementing a “lazy” allocation scheme which constructs interfaces only when requested by a client. The object implementation framework allows either strategy to be implemented with equal ease. The following code sample provides an example of the lazy allocation strategy. OLERandomNumberGeneratorObject supports the IRandomNumberGenerator interface, which it stores in an instance variable iRandomNumberGenerator. Its QueryInterface support method looks like the following: getInterfaceForIID: iid " Private - answer the interface identified by the GUID . Answer nil if the requested interface is not supported by the receiver. " iid = IRandomNumberGenerator iid ifTrue: [ " lazy allocation of a supported interface can be done as shown here " iRandomNumberGenerator isNil ifTrue: [ iRandomNumberGenerator := IRandomNumberGenerator on: self ]. ^iRandomNumberGenerator ]. ^super getInterfaceForIID: iid

408 Visual Smalltalk Enterprise Language Reference Implementing OLE Objects

The interface is constructed by sending the message on: to the interface class. For example, an IDataObject interface for an OLE object can be created by an expression of the form: IDataObject on: self The result is an IDataObject interface with a binding which dispatches invocations of the functions to the methods in your OLE object class. You must also implement two “housekeeping” methods in your OLE object subclass to support releasing the interfaces that have been allocated by your object during its lifetime. These methods are discussed later in the section Releasing an OLE Object. If the object you are implementing supports a large number of interfaces, which may not all be used during its lifetime, or if ease of implementation is more important that optimizing the size of your objects, you can implement your object class as a subclass of OLEObjectWithInterfaceStorage, an abstract subclass of OLEObject. This class allocates a dictionary to hold all the allocated interfaces supported by the object, with the IID of the interface used as the key to perform lookups in the dictionary. If you subclass OLEObjectWithInterfaceStorage, which has a standard implementation of getInterfaceForIID: which obtains allocated interfaces directly from the interface storage dictionary, you must reimplement the method createInterfaceForIID:, which simply returns a new instance of the requested interface if it is supported. This is slightly simpler to implement than getInterfaceForIID: and does not require an implementation of the two corresponding release support method, as must be done for an OLEObject subclass. Reusing OLE Objects Reuse of existing components is accomplished in COM through the mechanisms of containment and aggregation. When you implement an OLE object, you can create instances of other OLE objects whose services you use to implement the functions of your own object. When you create a contained object, you obtain an interface and can keep it as long as you wish to use the services of the inner object. Your object can use any services provided by an inner object through its supported interfaces, in the usual fashion. When you use containment in your OLE object implementation, you should reimplement the method releaseInnerObjects to release the inner objects that your containing object has created during its lifetime when it is terminated.

Visual Smalltalk Enterprise Language Reference 409 CHAPTER 20 OLE Support

Aggregation is a special case of containment which occurs when the controlling object wishes to directly expose an interface of an inner object as its own. This is useful when you wish to simply delegate the processing of all the functions of an interface directly to the inner object. Aggregation allows you to avoid the overhead of reimplementing all the functions of an interface when all your object needs to do is to relay the message to the inner object for processing. In your implementation of a controlling object, you obtain the IUnknown interface of the inner object when you create it; this is referred to as the “inner IUnknown” of the contained object. You can now expose any interfaces of the inner object as your own for the IUnknown::QueryInterface function by implementing suitable logic in the getInterfaceForIID: method of your class. You can either return an interface that your object supports directly, in the usual fashion, or obtain an interface from an inner object contained in your aggregate by querying its inner IUnknown interface for the desired interface. The OLEObject framework provides complete support for aggregation, so that any OLE object that you create can in turn be used by other objects through the mechanisms of containment and aggregation. If for some reason you create an object that you do not want reused within an aggregate, reimplement the method supportsAggregation to return false. Configuring Interface Function Processing When you construct an interface that is supported by your object, the interface binding will dispatch invocations of the functions in the interface to your object. For example, the binding for the IUnknown::AddRef function of the IUnknown interface will cause the message AddRef to be sent to your OLE object when the AddRef function is invoked. This interface is supported by every OLE object and must be included among the interface functions of every interface that you support for your object. Similarly, interface functions are dispatched to your OLE object for each function in an interface that you support. In many cases, the standard interface function dispatching is sufficient. When you decide to support an interface, you simply provide the necessary support for QueryInterface and for releasing, as described in the previous section, and implement methods in your class corresponding to the functions in the interface.

410 Visual Smalltalk Enterprise Language Reference Implementing OLE Objects

Note that you do not need to implement the IUnknown interface functions, since standard implementations of the interface negotiation and reference counting capabilities of an OLE object are provided by the OLEObject class. You should almost never reimplement these methods, with the possible exception of extending the QueryInterface processing in the implementation of the controlling object of an aggregate. To get a list of function names in VTable order, use the functionNames method defined in OLEInterface class. For example: IDataObject functionNames You can also read the VTable order from the C++ header files. Another OLEInterface message, describeInterfaceFunctions, returns more detailed information about the interface functions. In some cases, you may need to configure the interface function processing for your object in a more flexible manner than is provided by the standard dispatching connections, which simply send the message corresponding to the interface function to your object. For example, if you support two interfaces that contain a function of the same name, you will need to configure the interface function processing to invoke two separate methods in your object class to provide appropriate function processing for each of the two distinct interface functions. The Smalltalk interface support provides facilities that allow you to configure a customized interface binding when you need additional flexibility for your OLE object implementation. Interface function processing for an OLE object is configured by registering function dispatch handlers with the interface for the object. An interface function handler is usually a method in the implementing object, since the implementation of the desired behavior often requires access to the object’s private state. Also, the behavior provided for functions in different interfaces supported by the object often must be coordinated, which requires that the state of the implementing object to be known. An interface function handler need not be implemented as a method in the OLE object class, however. The function handler may be any evaluable action, including a block or a message sent to another object. Refer to the next section for more information on interface function handlers.

Visual Smalltalk Enterprise Language Reference 411 CHAPTER 20 OLE Support

An interface binding with customized function dispatching is typically constructed by an OLEObject instance in one of two ways, depending on whether the object implements all of its interface functions itself, or implements only some of its interface functions, possibly delegating others to another object. If the object itself implements all the interface functions, it can construct the supported interface using the on:selectors: class method, specifying itself as the implementing object and providing the list of message selectors to be sent to it for each function. The function processing selectors must be in VTable order when specified in this fashion. The message standardIUnknownSelectors can be sent to self to obtain the list of standard IUnknown function handler selectors. VTable selector lists should be constructed by using standardIUnknownSelectors and concatenating the remaining selectors of the interface to complete the VTable selector list. We recommend that, whenever possible, the interface function methods in your OLE object classes be named with the “raw” function name, using the native function name as the primary keyword of the method’s message selector (which typically with an uppercase first character) and the standard anonymous keyword for any additional argument keywords. This is the convention assumed by the standard interface function dispatching. In addition, using the “raw” function name for your method provides a tangible reminder that you are in an OLE interface function implementation, which has some special rules about how processing is implemented and results returned to the caller. If you find that you must implement two methods in your class to support functions with the same name, but from different interfaces, we recommend that you choose a simple convention to modify the basic message selector in a consistent way so that your method selector reflects in an obvious way the interface function name and the containing interface. If your object does not implement all the functions in an interface, or if it delegates processing responsibility to another object, you construct the interface for your object using the on: class method in the usual fashion and then reconfigure the function processing specifications as desired. The standard bindings will dispatch all of the interface functions to your object. You can reconfigure the dispatching specifications in several ways, allowing you great flexibility in specifying the function processing for an interface. A function dispatch handler for an interface binding is registered

412 Visual Smalltalk Enterprise Language Reference Implementing OLE Objects

using the standard registration messages of the Smalltalk event system, such as when:send:to:, with the name of the interface function specified as the event name. If you only implement a few functions in the interface, you can easily reconfigure the interface binding to support only the standard IUnknown functions and the specific functions for which you have implemented methods in your object. To install a minimal function binding specification, which dispatches the standard IUnknown operations to your operation and answers the E_NOTIMPL result code for all other functions in the interface, send the installMinimumDispatchHandlers to the interface binding that you are constructing. You can then configure the function processing for the specific functions that you support using the standard registration facilities of the Smalltalk event system. This makes it easy to support an interface in which you need to implement a few functions, without having to implement a large number of methods which do nothing besides returning E_NOTIMPL to the caller. If you wish to delegate processing of interface functions to an object other than the OLE object which supports the interface, simply configure a function handler which sends the appropriate message to the object which you wish to have perform the actual function processing. Implementing Interface Functions The majority of the logic in a subclass of OLEObject is the implementation of the function processing for the interfaces which are supported by the object. The methods that you implement and the private state that you maintain in your OLE object class are entirely determined by the purpose of your object and the behavior that you choose to give it. As with any Smalltalk class, you may use existing classes or create new classes as appropriate to produce the desired behavior in your OLE object. A function processing method should indicate an error condition by returning an appropriate HRESULT result value. It should not signal the OLEError exception. By design, signalling OLEError is the responsibility of OLE interface pointer and interface implementation classes. Signalling OLEError in a function handler is at best redundant and at worst will return a nonspecific result code to an external caller in an expensive way. All the standard HRESULT values are defined in the OLEStatusCodeConstants pool.

Visual Smalltalk Enterprise Language Reference 413 CHAPTER 20 OLE Support

Output arguments are provided by the caller as value references. Your function handler method sets the value of an output argument by sending the value: message to the caller’s reference. A function processing method must follow the OLE rules for interface reference counting and memory allocation when an interface or a block of memory allocated by the callee is returned to the caller. An interface returned to the caller must be reference counted by the callee. This is usually done either by obtaining a separate reference to an interface using the standard IUnknown::QueryInterface service or by sending separateReference to a known interface instance. Memory that is allocated by the callee and returned to the caller must be allocated using the OLE task allocator. Reference counting is discussed in more detail in Managing Object References. Memory management and using the OLE task memory allocator is discussed in Managing Memory. Releasing an OLE Object A Smalltalk OLE object maintains an overall reference count on the object, which is incremented and decremented as its interfaces are reference counted. The reference count of an OLEObject instance is set to zero when the object is created. The reference count is incremented and decremented each time the IUnknown::AddRef and IUnknown::Release functions are invoked on any interface supported by the object. When the reference count is decremented to zero, you can assume there are no longer any clients of any of the interfaces supported by your OLE object. Under the OLE reference counting rules, an OLE object is allowed (and indeed expected) to release its resources and destroy itself when its reference count reaches zero. Termination processing of an OLE object is implemented in the method releaseResources. The standard cleanup performed by the implementation in OLEObject includes releasing the external resources of all supported interfaces. This is an important service, because each interface that you supply to an external client causes external memory to be allocated. This memory is not managed by the Smalltalk object memory manager, and must be explicitly released. To support releasing the resources of interfaces supported by your object, you must reimplement two methods: • allocatedInterfacesDo:, which must evaluate a one- argument block on each interface that has been allocated during the object’s lifetime

414 Visual Smalltalk Enterprise Language Reference Implementing OLE Objects

• resetAllocatedInterfaces, which clears any references to the deallocated interfaces. Note that these two methods do not need to be implemented if you have subclassed OLEObjectWithInterfaceStorage. For example, the cleanup methods in the OLE random number generator object are as follows: allocatedInterfacesDo: aOneArgBlock " Private - enumerate the interfaces supported by the receiver which have been allocated during its lifetime and evaluate with each. " super allocatedInterfacesDo: aOneArgBlock. iRandomNumberGenerator notNil ifTrue: [ aOneArgBlock value: iRandomNumberGenerator ]. resetAllocatedInterfaces " Private - reset the references to the interfaces supported by the receiver. " super resetAllocatedInterfaces. iRandomNumberGenerator := nil. The releaseResources method should be reimplemented in any subclass of OLEObject whose instance state contains resources other than supported interfaces which should be released when the object’s lifetime is terminated. Returning Values from an Interface Function OLE interface functions are almost always designed to conform to the convention that the return value of the function is an HRESULT value, which provides the caller with a status code describing the outcome of the function. Output values are returned to the caller through OUT arguments, which the callee sets if the function succeeds. The standard HRESULT status codes are defined as pool variables in the pool OLEStatusCodeConstants. When you implement a function in your OLE object, you can answer an HRESULT as the return value of the function using these constants. Arguments to your interface function that have OUT semantics are provided by the interface binding mechanisms as reference values. In your interface function method, you return a value for an OUT parameter by sending the message value: to the reference

Visual Smalltalk Enterprise Language Reference 415 CHAPTER 20 OLE Support

argument that is provided. Note that you should never set the value of an output argument unless you are also returning a success result code from your function. For example, the sample OLERandomNumberGenerator object implements the function IRandomNumberGenerator::Next as follows: Next: resultReference " Private - implement the RandomNumberGenerator::Next operation. " resultReference value: self computeNextValue. ^S_OK As with most OLE interface functions, this function returns a value to the caller by sending value: to the reference argument to set the return value and answers an HRESULT status code which indicates whether the function succeeded. Implementing Reference Counting OLE objects implemented in Smalltalk must implement the OLE reference counting rules for the interfaces they support whenever interfaces are returned from a function implementation to the caller. Every time a request is made for an OLE interface, the supporting object must return a new reference to that interface and increment the count for that interface by one. To do this in Smalltalk, send the message separateReference to the interface instance. For example, the standard implementation in OLEObject of IUnknown::QueryInterface returns a separately reference counted copy of the interface to its caller as the return value of the function. There are two standard patterns in Smalltalk OLE object interface function implementations for returning an interface to a caller as the value of an output argument. To return an interface to which your object already has a reference, use the separateReference message when setting the value of the output argument. For example, if your OLE object has acquired some interface that it uses in its processing and has the interface saved in an instance variable. In this case, you would return this interface to a caller using an expression such as the following: resultReference value: someInterface separateReference.

416 Visual Smalltalk Enterprise Language Reference Implementing OLE Objects

The second pattern occurs when you return an interface which you obtain by asking some other OLE object for a reference to a particular interface. This is typically done using an expression of the form: resultReference value: ( anInterfaceInstVar queryInterface: iid ). Since the queryInterface: message always returns a separately reference counted interface to the caller, you return this directly to the caller. There are also reference counting rules that apply to interfaces passed as input arguments to a function. An interface that is passed as a function argument does not need to be reference counted by the caller and can be freely used by the callee for the duration of the function invocation. Within the implementation of an interface function in an OLE object that you implement, you do not have to do anything if you only use an interface argument during the actual function call. Do not increment the reference count of the interface, and do not release it. In most cases, this means that you can use the interface arguments in your function implementation without worrying about reference counting. If your implementation of an interface function needs an interface argument for use after the function is completed, however, you must keep a separate reference to the interface argument. For example, to save an interface argument in an instance variable of your OLE object for later use, you would evaluate an expression of the form: someInterface := anInterfaceArgument separateReference. Since your object now owns a new, separately reference counted copy of the interface, you are responsible for controlling the lifetime of the reference and must release it when finished using it. These two patterns cover most of the situations that you will encounter when implementing an OLE object in Smalltalk. Special situations may arise as a result of shared use of an interface or in cases where reference counting cycles can occur. These can generally be resolved by remembering that an interface is an object in Smalltalk and analyzing the lifetime characteristics of how the interface is used by the various clients. If the interface needs to be used by another object and the lifetime of that usage is not known to be contained within the lifetime of the owner’s usage, a separately reference counted copy of the interface should be created.

Visual Smalltalk Enterprise Language Reference 417 CHAPTER 20 OLE Support

Reference counting cycles can occur in situations where two objects are mutually dependent, with each holding interface references to the other. This situation can be resolved by making suitable exceptions to the normal reference counting rules, after careful analysis of object dependencies and lifetimes. Memory Management In an earlier section, it was explained that an application is responsible for releasing any memory block received from an interface or API function call. This applies also to OLE object implemented in Smalltalk. You must follow the OLE memory allocation rules when you are implementing an interface function in an OLE object that is responsible for allocating and returning memory to the caller. In this case, you must use the OLE task allocator to allocate the memory. The class OLEMemoryAddress is used to allocate memory blocks using the OLE task allocator. To allocate a block of memory, send the class message allocateMemory: to OLEMemeoryAddress, specifying in the message argument the size in bytes of the memory to be allocate. All in/out parameters passed to an OLE function or returned from an OLE interface implementation as the value of an out parameter that contain a pointer to a memory block must be allocated in this way. An OLEStructure subclass which defines an OLE data structure can be allocated using the OLE task allocator by sending the message newExternalStructure to the appropriate structure class. There are also services provided by the OLEStructure class to allocate structures that can be returned to a caller as output argument values. For example, if you implement a function that returns a newly allocated POINTF to the caller, your function implementation can allocate the return value as follows:

418 Visual Smalltalk Enterprise Language Reference COM Infrastructure Support

aPointStruct := (OLEStructure createExternalStructureNamed: #POINTF). aPointStruct x: 0; y: 0; resultReference value: aPointStruct. ^S_OK. COM Infrastructure Support Several basic COM infrastructure technologies are supported in Visual Smalltalk. Basic OLE Data Types Globally Unique Identifiers A globally unique identifier (GUID) is a 16-byte (128 bit) value which is guaranteed to be unique. GUID values are used extensively in OLE, for example as OLE object class identifiers (CLSID) and interface identifiers (IID). In Smalltalk, the class GUID contains GUID values. A GUID can be created by sending the message asGUID to a string containing the display name of an GUID. There are also instance creation messages in the GUID class which invoke OLE API’s to obtain GUID values. A new GUID is allocated by evaluating the expression GUID new. HRESULT Values The standard convention, used by almost all OLE interface and API functions, is to return an HRESULT status code as the function result value. The abstract class HRESULT provides the standard OLE services for testing HRESULT values, as well as for accessing fields and constructing HRESULT values. For example, the standard test for a successful HRESULT that is commonly used in OLE client applications is expressed as follows: | hresult | hresult := anInterface someFunction: ... " invoke some interface function " ( HRESULT succeeded: hresult ) ifTrue: [ ... success logic ... ] ifFalse: [ ... error handling ... ].

Visual Smalltalk Enterprise Language Reference 419 CHAPTER 20 OLE Support

The HRESULT class also provides utility services for obtaining information about an HRESULT code such as the error message defined by the operating system or a string describing the condition represented by an HRESULT. OLE Enumerators Enumeration is provided in OLE by a family of interfaces that enumerate collections containing a specific element type. Collections are homogeneous and each element type has a unique interface defined for enumerating collections of that type. In Smalltalk, enumerators of all element types are supported by the interface class IEnum. An enumerator interface that is returned by an API or interface function is instantiated by sending the class creation message forReturnValue:, with the IID of the enumeration interface of the desired element type class provided as the argument. Supported enumeration element types are either an interface class, such as IUnknown, or a data structure, such as OLEVERB. The IEnum interface instance that is created has an instance-specific IID which identifies the underlying OLE interface defined for elements of that type. The standard OLE enumerator interfaces and their element types are predefined in the IEnum class. Additional enumerator interfaces can be supported by registering the IID and the element type in IEnum enumerator registry. Register an interface and type by sending the class message: IEnum registerEnumeratorIID: aGUID for: aClass Enumerators are implemented in Smalltalk by the OLEEnumeratorObject class. An enumerator object is created using the on: class creation message, providing a homogeneous collection of interface or data structure instances as the argument. The enumerator object can then be used to enumerate the elements of the collection. The enumerator interface supported by the enumerator object has an instance-specific IID that is determined using the facilities of IEnum which map element type classes to the appropriate IID. OLE Monikers An OLE moniker is a reference to an object that can be stored in persistent external storage and reloaded in the future. The primary operation of a moniker is to bind to the referenced object. Monikers are used in OLE containers to reference linked objects,

420 Visual Smalltalk Enterprise Language Reference COM Infrastructure Support

but are also of broader use and as such constitute a distinct infrastructure technology of COM. The IMoniker class is the interface class for the primary interface to OLE monikers. OLE provides a number of standard system moniker types, such as file, item, and composite monikers. The IMoniker class provides a number of class messages to create new instances of the system- supported monikers. OLE Structured Storage Support One of the basic technologies of OLE is structured storage, which is a hierarchical model of persistent storage similar to the directory/file model of hierarchical file systems. OLE structured storage is used by container applications to manage their compound document file. OLE storages and streams provide support for various storage and access modes. An OLE storage is a directory-like object, which can contain streams and other storages. An OLE stream contains data bytes. The OLE structured storage facilities include support for managing shared access to storage elements and a transaction model for controlling how changes in working state are committed to persistent storage. The COM persistent storage facility is also referred to as compound document storage. A structured storage file containing a compound document is also referred to as a compound file or a compound document file. The IStorage interface provides operations on storages. An IStorage provides services to create or open the streams and substorages that it contains, enumerate its contents, move and copy elements between storages, rename elements, delete elements, and commit changes to the contents or revert to the original state of the contents. An OLE storage that exists as a file in the file system is accessed using the class OLECompoundFile, which is an IStorage with additional class services to create and open a root storage document file. The IStream interface is used to read and write the underlying bytes in a stream. An IStream provides services to read and write data bytes and to commit changes, or to revert to the original state of the stream. An OLEReadWriteStream is a Smalltalk stream on the data bytes of an IStream. As with the file system classes File and FileStream, to which IStream and OLEReadWriteStream correspond, most

Visual Smalltalk Enterprise Language Reference 421 CHAPTER 20 OLE Support

operations on a data stream by a Smalltalk client are done through the OLEReadWriteStream instance, with the underlying IStream instance rarely manipulated directly. An OLE stream can support either byte or character semantics for interpreting the underlying data bytes. You can obtain an OLE stream by sending the message asStream to an IStream instance. The default interpretation is to support character semantics, for consistency with the string-oriented behavior of the existing Smalltalk Stream classes. To specifically create a byte or character OLE stream, send the message asByteStream or asCharacterStream to the IStream. OLE Uniform Data Transfer Support Uniform Data Transfer is a set of interfaces that allows OLE applications to exchange data in a standard way. Central to uniform data transfer is the IDataObject interface, which allows a data transfer object to communicate to the outside world. An application that implements a data transfer object which supports the IDataObject interface can use that object in any clipboard or drag drop transfer. The IDataObject interface contains methods for retrieving, setting, querying, and enumerating data, and handle data exchange notifications. Clipboard OLE clipboard support is provided using the IDataObject interface. A server application places an IDataObject on the clipboard, while a data consumer obtains an IDataObect from the clipboard. OLE provides two APIs for setting and retrieving data from the clipboard: OleGetClipboardData and OleSetClipboardData. These APIs are wrapped in the methods getClipboardObject in IDataObject, and copyToClipboard in IDataObject and OLEDataTransferObject. The API OleFlushClipboard empties the clipboard and removes the IDataObject instance. This API is wrapped by the class method flushClipboard in IDataObject. The following code fragment demonstrates copying data to the clipboard: dataTransferObject := OLEDataTransferObject new. dataTransferObject setObject: ‘Hello world’ format: 'String'. dataTransferObject copyToClipboard

422 Visual Smalltalk Enterprise Language Reference COM Infrastructure Support

The following code fragment demonstrates pasting data from the clipboard iDataObject := IDataObject getClipboardObject. ( string := iDataObject renderFormat: 'String' ) isNil ifTrue: [ MessageBox warning: 'invalid format' ]. .... iDataObject release Drag Drop The Visual Smalltalk drag/drop framework has two classes which are vital to understanding this framework: DragDropObject, which represents the objects being dragged, and DragDropSession, which models the drag/drop transfer and manages the interaction between the source and target. Refer to chapter 6, Drag/Drop, for a full discussion of the drag drop framework. Enabling OLE Drag/Drop The messages described above enable a window for OLE drag/drop. For example, to make a text pane a drag target include the message dragTargetGlobal in the creation method of the text pane. The following code fragments demonstrate how to set up a list box as a drag source and target. The following example sets up the list box for local Visual Smalltalk drag/drop: aToppane addSubpane: ( ListBox new owner: self; setName: #target; dragSource; when: #dragSourceNeedsObject: send: #dragSourceNeedsObject: to: self ; when: #dragSourceCut: send: #dragSourceCut: to: self ; dragTarget; dragTargetForFormats: #( 'string' ) operations: #( #move #copy ); when: #dragTargetDrop: send: #dragTargetDrop: to: self ; when: #needsContents send: #targetContents: to: self with: target ; framingRatio: ( Rectangle leftTopUnit extentFromLeftTop: (1/2)@(1/2) ); yourself ); The next example sets up the list box for OLE drag/drop:

Visual Smalltalk Enterprise Language Reference 423 CHAPTER 20 OLE Support

aToppane addSubpane: ( ListBox new owner: self; setName: #target; dragDropGlobal; when: #dragSourceNeedsObject: send: #dragSourceNeedsObject: to: self ; when: #dragSourceCut: send: #dragSourceCut: to: self ; dragTargetForFormats: #( 'string' ) operations: #( #move #copy ); when: #dragTargetDrop: send: #dragTargetDrop: to: self ; when: #needsContents send: #targetContents: to: self with: target ; framingRatio: ( Rectangle leftTopUnit extentFromLeftTop: (1/2)@(1/2) ); yourself ); Notice the only difference is that the second example uses the message dragDropGlobal to enable the list box as an OLE drag source and target. OLE Drag/Drop Implementation OLE drag/drop support is implemented as an extension to basic Visual Smalltalk drag/drop support. OLE drag/drop uses the same events and messages as local drag/drop. The only difference is that with OLE drag/drop, users can do inter-process drag/drop. OLE drag/drop adds two classes: WinDragDropObject and WinDragDropSession. An instance of WinDragDropObject represents an object that is being dragged in a drag drop session. It has one instance variable, formats, which contains a dictionary whose keys are the available data formats and values are the corresponding data. When a drag drop session is initiated, the session requests a collection of WinDragDropObject instances from the source by triggering the sourceNeedsObject: event. In addition to inheriting the methods from DragDropObject, WinDragDropObject defines the following new methods: availableFormats Answer an ordered collection of strings identifying the formats available in the receiver. format: formatTypeString Answer data in the specified format, or signal an error if no such format is available.

424 Visual Smalltalk Enterprise Language Reference COM Infrastructure Support format: formatTypeString data: formatData Set the data for the given format to formatData. format: formatTypeString ifAbsent: aBlock Answer data of the given format, or answer the result of evaluating aBlock if no such format is available. hasFormat: typeNameString Answer whether the receiver can provide data in the given format. Formats are typically determined by the drag/drop source. The following are the possible data transfer objects and the corresponding format type string:

Object Format Type String

String ‘String’ Bitmap ‘Bitmap’ DIB ‘DIB’ StoredPicture ‘Metafile’ FileName ‘FileName’ Embedded OLE object ‘Embedded Object’ or ‘Embed Source’ ObjectDescriptor ‘ObjectDescriptor’ Linked OLE object ‘Link Source’ LinkedSourceDescriptor ‘'Link Source Descriptor'

An instance of WinDragDropSession models the OLE drag/drop transfer and manage the interaction between the drag source and target. WinDragDropSession inherits protocol from DragDropSession, and adds the following additional public protocol: Class Methods objectClass Answer the class to use for drag/drop objects which are added to objects of the receiver class. fromIDataObject: anIDataObject Answer a new instance of the receiver from the specified iDataObject. The following public methods have been added to class Window to enable and disable OLE drag drop:

Visual Smalltalk Enterprise Language Reference 425 CHAPTER 20 OLE Support

dragDropGlobal Enable the receiver as an OLE drag source and target. dragSourceGlobal Enable the receiver as an OLE drag source. dragTargetGlobal Enable the receiver as an OLE drag target. OLE Automation OLE Automation provides a way for an application to programmatically manipulate objects in another application. Such an application is called an OLE automation controller. OLE automation objects provide services in a standard way by supporting the IDispatch dispatch interface, which allows clients to invoke methods and to get and set properties of the automation object. The capabilities of an automation object and the type information needed to invoke its methods and property members are described in type libraries. Using OLE Automation Objects The OLEDispatchDriver class simplifies developing an OLE automation controller by providing facilities which make it easy to invoke the methods and property members of an OLE automation object. An OLEDispatchDriver is configured by providing it with the IDispatch interface of an automation object, and with specifications describing the methods and properties supported by that object. Once you have configured a dispatcher for an automation object, you can invoke its methods and access its properties simply by sending messages to the dispatcher, with normal Smalltalk values used as the argument and return values. The dispatcher handles all the mechanics of transforming the argument and return values into dispatch value encodings and invoking the requested method or property function. As with other OLE interface functions, error conditions resulting from a dispatch function invocation cause an exception to be signalled with information describing the error. Methods and properties supported by an automation object are described by specifications, which contain the identification and type information needed to invoke the dispatch interface member. Specifications are instances of concrete subclasses of OLEDispatchMemberSpecification. The abstract superclass provides services which construct the specifications for the methods and properties of an automation object from its type

426 Visual Smalltalk Enterprise Language Reference OLE Automation

library information. This greatly simplifies the development of an OLE automation controller, by making it easy to configure an OLEDispatchDriver with the specifications which allow you to invoke dispatch functions naturally in your Smalltalk application using the services of the dispatcher. Implementing OLE Automation Objects You can implement automation objects by creating subclasses of the abstract class OLEAutomationObject, which provides the basic OLE object implementation for supporting IDispatch. In your subclass, you must provide an appropriate implementation for the IDispatch::Invoke function, as well as for any other IDispatch functions or other interfaces that your object supports. You can also use the generalized automation object OLEAutomationServer to publish an object as an OLE automation object. An OLEAutomationServer is configured by providing it with the object to be published and the dispatch member specifications for the methods and properties supported by your object. The automation server that you construct to publish an automation object supports the IDispatch interface using the specifications that you provide. When a client invokes a method or property member of the published object, the automation server handles the mechanics of transforming argument and return values between the dispatch value encodings and appropriate Smalltalk values. It also performs the member function processing by sending the message defined in the specification of that dispatch member to the published object. OLE Event Support OLE defines a generalized event model based on the dispatch technology which is the foundation of OLE automation. The OLE event system provides for connecting an object which generates events with clients who are interested in receiving notifications of those events through a dispatch interface connection. An OLE object that generates events supports an outgoing dispatch interface for each event set that it supports. An interested client registers to receive event notifications by constructing a matching dispatch interface which it connects to the event source. This allows the object generating the events to notify clients when the event occurs by invoking the appropriate member function in the dispatch interface.

Visual Smalltalk Enterprise Language Reference 427 CHAPTER 20 OLE Support

You can construct an event sink through which event notifications are received by creating an instance of OLEEventSink. An event sink is configured by providing it with the IID of an event set interface and specifications describing the supported events. As when configuring a dispatch driver to use an automation object from another application, there are services provided in the abstract class OLEDispatchMemberSpecification which will construct the dispatch member specifications for an event set from its type library information. An OLEEventSink handles the mechanics of establishing a connection with an event source object and providing transformations between dispatch value encodings and appropriate Smalltalk values when an event notification is received. When an OLEEventSink receives an event notification from the OLE event source object to which it is connected, the event sink triggers a Smalltalk event. The event names that are triggered are determined by the selectors defined in the dispatch member specifications that are provided for each event when you configure the event sink. In your application, you can configure an OLEEventSink and then register event handlers for OLE events using the standard facilities of the Smalltalk event system. OLE Support Framework OLE interfaces are typically provided by OLE servers external to Visual Smalltalk. To use such an interface in a Visual Smalltalk application, it must be wrapped by Smalltalk classes and methods. In this final section, we describe the framework provided by Visual Smalltalk for representing interfaces for use in an application. It is assumed in this section that you already know how to access OLE interfaces from another language, such as C, and so you only need specific pointers to implementing the same functionality in Smalltalk. OLE Pools Support for OLE employs these pools: OLEAutomationConstants Constants used in OLE automation applications OLEConstants OLE constants and enumerated type values.

428 Visual Smalltalk Enterprise Language Reference OLE Support Framework

OLEControlConstants Constants used in OLE controls OLEStatusCodeConstants OLE function status codes and HRESULT values. OLEUIConstants Constants and enumerations for OLE UI common dialogs. The pool variables contained in these pools are exactly those defined as the constant name in the C header files. OLE Data Structures OLE data structures are implemented as subclasses of the abstract class OLEStructure, under ExternalBuffer. These classes define methods for manipulating OLE-specific data types in structure fields. Structures are allocated using the class messages defined in OLEStructure. OLE Function Binding Classes The framework both allows accessing OLE objects defined outside Smalltalk, using callout facilities, and implementing OLE objects in Smalltalk, allowing callin access by client objects. A typical OLE application involves an exchange between externally defined and internally defined OLE objects. The OLE support framework uses the following classes specifically for implementing OLE interfaces. OLEDynamicLinkLibrary The OLE API functions are supported by API primitive methods in subclasses of OLEDynamicLinkLibrary. The abstract superclass provides utility services to support native API function invocation. OLE API functions should usually be invoked through messages supported by the appropriate OLEInterface class. OLEInterfacePointer An interface has a binary representation in memory consisting of a pointer to a pointer to a list of functions. Instances of OLEInterfacePointer are the first of these pointers, which point to entries in the VTable. An interface pointer class defines the OLE function primitives, which directly invoke a native host function in the interface. Subclasses of OLEInterfacePointer have the following responsibilities:

Visual Smalltalk Enterprise Language Reference 429 CHAPTER 20 OLE Support

• implement public protocol for the interface functions • perform argument transformations between Smalltalk objects and host data types • implement methods to call OLE function primitives • signal OLE exception conditions to a Smalltalk caller The OLEInterfacePointer class hierarchy should parallel the OLEInterface hierarchy, providing the same inheritance structure. Each interface pointer class is uniquely identified by its IID, which can be obtained by sending the iid message to the interface. The public protocol of an interface pointer class should consist of exactly the interface of the interface functions. “Civilizing” functions should not be defined in these classes. Calling an OLE function is similar to making an API call, but employs the special ole calling convention for invoking a function entry point in an interface VTable. OLEInterfaceImplementation Interfaces are implemented in Smalltalk as subclasses of OLEInterfaceImplementation. These primarily provide callin services allowing external clients to invoke an OLE object implemented in Smalltalk. The OLEInterfaceImplementation classes provide the callin binding to allow external clients to invoke interfaces supported by an OLE object implemented in Smalltalk. Since all interfaces support IUnknown, all implementations are defined under IUnknownImplementation. An interface implementation manages the interface data structure in external memory, and dispatches function processing to support invocation of its interface functions. The OLEInterfaceImplementation class hierarchy should parallel the OLEInterface hierarchy, providing the same inheritance structure. Each interface implementation class is uniquely identified by its IID, which can be obtained by sending the iid message to the interface.

430 Visual Smalltalk Enterprise Language Reference CHAPTER 21 SOM Support Overview Visual Smalltalk for OS/2 includes SOM support as an add-on component contained in a Smalltalk library. Once installed in the image, you can access SOM objects from Visual Smalltalk, add subclasses and methods to the SOM objects, including inheriting and overriding the SOM objects’ methods. SOM objects are defined in a hierarchy of classes, with methods defining the object behavior, in a manner similar to the way Smalltalk does. To use SOM objects within Visual Smalltalk, you define proxy classes and methods within the class hierarchy. When a proxy message is sent, the corresponding SOM method is invoked by a SOM API call. The SOM support library defines a large number of proxy classes for standard SOM classes and a number of proxy classes for standard SOM type definitions. It also provides a framework for interacting with SOM and creating your own proxy classes. Installing SOM Support Basic operating system support for SOM is installed with OS/2 Warp. You need to modify the SOM interface repository so that the samples classes, defined in the CFILES directory, are recognized. Modify your CONFIG.SYS file so that the SOMIR environment variable includes the sample interface repository in the CFILES subdirectory in its path. For example: SET SOMIR=C:\SOM\ETC\SOM.IR; C:\SmalltalkPath\EXTRAS\SOM\CFILES\TEST.IR; substituting the Visual Smalltalk installation directory path for SmalltalkPath. At this point, you can run the simple test, MAIN.EXE, to verify basic functionality. There is a makefile to remake the DLLs if you desire, or you can use the DLL files provided. If you use the makefile, it assumes that the following is also set in your CONFIG.SYS: SET SMSTAR=1

Visual Smalltalk Enterprise Language Reference 431 CHAPTER 21 SOM Support

Finally, bind the SOM support Smalltalk library using the Service Manager. Once installed, SOM support is ready for use. Running the SOM Demo For a demo and tutorial, open the file DEMO.WS workspace file and follow the instructions given there. The rest of this chapter describes the implementation and use of the Visual Smalltalk SOM bindings. When running the SOM server examples, be sure to start the DSOM daemon (SOMDD) before starting the servers. If you do not, the application will hang. SOM DLL Access Access to the SOM DLLs is provided through three DynamicLinkLibrary subclasses: SOMDLL defines the basic SOM DLL entry points SOMDDLL defines the entry points for SOMD SOMTCDLL defines the entry points for manipulating SOM typecodes Three global instances of these classes are defined for accessing these DLLs: SOMLibrary; SOMDLibrary; and SOMTCLibrary. SOM Proxy Base Classes The SOM Smalltalk library defines a collection of classes to act as superclasses for various kinds of SOM classes and typedefs. SOMProxyClass defines basic behavior for creating Smalltalk proxy classes for SOM classes, including instance creation and sundry housekeeping methods. All proxy classes for SOM classes should be direct or indirect subclasses of SOMProxyClass. The SOM library adds a number of proxy classes under SOMProxyClass. The methods in the proxy classes are a subset of the methods in the corresponding SOM classes. These proxy classes provide good base for both understanding and extending the SOM Proxy class hierarchy. SOMTypeCode implements behavior for SOM TypeCodes. TypeCodes are "pseudo-objects" in SOM, and so do not behave exactly like SOM objects. The SOMTypeCode class provides easy access to TypeCode behavior.

432 Visual Smalltalk Enterprise Language Reference SOM API Conventions

SOMProxyTypeDef defines the basic behavior for most typedef proxies. This is an abstract class with a number of concrete subclasses for specific types of SOM typedefs, including SOMSequence, SOMAny, SOMArray, SOMEnumeration, SOMForeign, SOMStructure, and SOMUnion. In addition, SOMPointer is defined as a SOM typedef but as a subclass of ExternalAddress. SOM API Conventions Two api calling conventions have been added to Visual Smalltalk to support SOM: • somapi is used to send a message to a SOM object. • indirectC is used for accessing the SOM DLLs. Each of these are slight variations on the normal API calling conventions and so are described here by their differences. Methods implemented using the somapi calling convention must be defined in classes that inherit from SOMProxyClass. SOMProxyClass defines a single instance variable, object, which is the handle for the SOM object. The following is an example of a somapi method: somdNewObject: receiver environment: environment objclass: aString1 hints: aString2 self invalidArgument The method name is somdNewObject. Each of the parameters, including the receiver, must be explicitly specified, and the return type completes the specifications. C functions that return structures do so with an implicit extra parameter inserted at the beginning of the parameter list. SOM makes frequent use of function pointers in its DLLs. To simplify using these DLL entries, Visual Smalltalk provides the indirectC calling convention. This convention is used exactly as the c or api conventions, except that the DLL is expected to hold a pointer to the function instead of the function itself at the DLL entry point. For example: somMalloc: aSize self invalidArgument

Visual Smalltalk Enterprise Language Reference 433 CHAPTER 21 SOM Support Type Mappings SOM defines a basic set of parameter types allowed in SOM methods. These types map into Visual Smalltalk data types as follows:

SOM parameter type Visual Smalltalk data type SOM integer types (short, long, unsigned Integer short, unsigned long, and octet) boolean Boolean char Character

double Float float (single precision) not supported string String any SOMAny TypeCode SOMTypeCode object subclass of SOMProxyClass struct subclass of SOMStructure union subclass of SOMUnion enum subclass of SOMEnumeration sequence SOMSequence array SOMArray pointer SOMPointer

All other SOM parameters map onto predefined or newly defined proxy classes.

434 Visual Smalltalk Enterprise Language Reference Using SOM Objects in Smalltalk

Using SOM Objects in Smalltalk To use a predefined SOM object from Smalltalk, you need at least an interface repository file (.IR), which identifies objects to SOM, and a DLL file containing the object. To modify SOM object behavior, you also need the object interface definition file (.IDL). SOM Initialization Some code will require that SOM be fully initialized before executing. To allow you to make your application wait, the SOMControlManager class triggers the event SOMStarted when it is finished initializing the SOM environment. You can use this event by registering handlers for the SOMStarted event, and build your application so that code is only executed when the event is triggered. Create Proxy Class Each SOM class must be represented in the Smalltalk image by a proxy class. This class is defined as a subclass of SOMProxyClass, and probably of SOMObject. The class can then inherit methods from SOMProxyClass necessary to send messages to the SOM object. Create Proxy Methods Each SOM method should be represented by a Smalltalk method that makes the SOM message send by making a SOM API call. Visual Smalltalk allows the underscore character (_) in identifiers. This greatly simplifies mapping SOM names to Visual Smalltalk names since the identifiers in the two spaces are now composed from the same character sets. The SOM API method uses the somapi calling convention. Methods using the somapi calling convention must be defined in classes that inherit from SOMProxyClass. The following is an example of a somapi method: somdNewObject: receiver environment: environment objclass: aString1 hints: aString2

self invalidArgument

Visual Smalltalk Enterprise Language Reference 435 CHAPTER 21 SOM Support

The method name is somdNewObject. Each of the parameters, including the receiver, must be explicitly specified, and the return type completes the specifications. C functions that return structures do so with an implicit extra parameter inserted at the beginning of the parameter list. Generally, a second method is defined to “wrap” the api method. This method is responsible for converting the Smalltalk objects into a form usable by the api method and converting the results of the api method into more useful Smalltalk objects. Wrapper methods then become the public interface in Smallatlk to the SOM object. Inheritance Proxy classes use inheritance to parallel the SOM class and method definition structure. Since SOM supports multiple inheritance and Smalltalk supports only single inheritance, some way is required to resolve this incompatibility. One approach is to always inherit from the primary parent defined in SOM and redefine non-inherited methods as necessary. For example, imagine a class X that defines a method x and a class Y that defines a method y. A class Z that inherits from X and Y in SOM would inherit both methods x and y. In the Smalltalk proxy class, Z would inherit from X and define a method y that was equivalent to the method found in class Y. Memory Management Objects, TypeCodes, and the memory used to store structures and unions is under the control of the programmer and must be manually freed. This task is complicated by the lack of strong conventions of ownership of each of these entities. Visual Smalltalk generally keeps memory in Smalltalk space since TypeDefProxy is a subclass of ExternalBuffer. The virtual machine copies the data to non-Smalltalk memory during a call to the API and copies the modified buffer back afterward, and then deletes the memory. This assumes that Visual Smalltalk owns the memory. Sometimes, memory ownership is transferred during a method call, and the object implementing the method takes responsibility for the memory. In this case, it would be an error to delete the memory. Objects and typedefs pose similar problems. They must be freed when no longer needed, but must only be freed by the "owner" of the object.

436 Visual Smalltalk Enterprise Language Reference Using SOM Objects in Smalltalk

Unfortunately, memory and object ownership is decided on a method by method basis and great care must be taken in analyzing memory and object ownership. Objects are freed by sending the message somFree to the object. TypeCodes are freed by sinding the message free to the TypeCode. Memory is freed by sending the message SOMFree: to SOMLibrary with the memory to be freed as its parameter. Objects allocated through DSOM must be freed differently. They are freed by sending somdDestroyObject: to the SOMD_ObjectMgr with the object as a parameter. For example: (SOMDLibrary getObjectVariable: 'SOMDObjectMgr') somdDestroyObject: myObject. To free memory allocated by DSOM for return values or OUT parameters, you must send the ORBFree: message to the SOMDLibrary, instead of SOMFree. Implementing SOM Methods in Smalltalk You can add behavior to a SOM class in Visual Smalltalk, and so use Visual Smalltalk as an implementation language for SOM classes. To do so, you use the callback mechanism described earlier in this chapter. You must create a SOM IDL file defining the SOM class interface for any methods you will implement in Visual Smalltalk, and register it with the SOM interface repository. Use the SOM compiler as usual to create the C stub files and compile them into a DLL and LIB file. (Refer to the SOMobjects documentation for further instructions.) You do not insert method implementation code in the stub files since you will do this in Visual Smalltalk. The file DEMO.WS, which you can open as a workspace, describes how to load and run an example of implementing a SOM method within Visual Smalltalk. Several sample files are included in the SAMPLES\SOM\CFILES subdirectory showing how to build the necessary files in C. The CALLBACK.ST installation script provides the classes and methods that define the callback processing and access that processing through a call to the SOM API.

Visual Smalltalk Enterprise Language Reference 437

CHAPTER Multiple Document 22 Interface (MDI) Overview MDI is a Microsoft Windows user interface standard for presenting and manipulating multiple documents within a single application. Visual Smalltalk for Windows platforms provides MDI classes that fully support MDI capabilities, as defined and implemented in Windows 3.x by Microsoft. Visual Smalltalk’s MDI support classes provide interface support for both the development and runtime environments. If you, as a developer, like working in the MDI environment, you can activate it. You can also develop the user interface for your application using MDI, giving your end-users an enhanced interface. For more information about MDI, please refer to the Microsoft documentation. For examples of MDI client/server applications, examine the SAMPLE\MDI subdirectory in the Visual Smalltalk directory. Two MDI examples are provided: SysEdit and MDIDemo. Installing MDI Classes MDI support is an optionally installable feature. Using the Service Manager, install: • MDI Support (Visual Smalltalk) • MDI Development Support (Visual Smalltalk Enterprise) Delivering an MDI Application If you use MDI support in your application, remember to provide the MDI Support Smalltalk library (VMDInnp.SLL) with your application. The library may be statically or dynamically bound to the application image. You are not allowed to provide the MDI Development Support libraries (VMDDnnW.SLL and 'TMMDDnnW) with your application. Make sure these libraries are not bound when you build the application image.

Visual Smalltalk Enterprise Language Reference 439 CHAPTER 22 Multiple Document Interface (MDI) Activating MDI Mode When MDI support classes have been installed, you can activate MDI mode for use in your development environment.

NOTE: Switching to MDI closes all currently open windows without saving changes. You are not prompted to save edited text panes. The Transcript reopens in MDI mode with the original text intact.

To activate MDI, select the MDI Mode item in the Options menu. This menu item acts as a toggle. The menu item is checked when MDI mode is activated and unchecked when MDI mode is deactivated. Figure 22-1 illustrates the Transcript when MDI mode is active. You can also evaluate the following expressions. To activate MDI, evaluate using DoIt: MDISystem activate To deactivate MDI, evaluate using DoIt: MDISystem deactivate

Figure 22-1: Visual Smalltalk in MDI Mode

440 Visual Smalltalk Enterprise Language Reference Activating MDI Mode

The bottom pane, called the status bar, displays messages relating to the multiple-pane environment. For example, when you select one of the icons in the tool bar, text describing the function of that tool displays in the status pane. Icons selected from the tool bar perform the following functions: Opens another workspace Opens an existing file Opens a File Dialog to file-in a file Saves the modified text of the active text pane Prints the active text pane or window Saves the image Cuts the selection and saves it on the clipboard Copies the selection and saves it on the clipboard Replaces the selection with the contents of the clipboard Evaluates the selected text and displays the result Compiles and executes the selected text Opens an inspector on the result of evaluating the selected text Compiles and evaluates the selected text in change log format Finds global references Opens a When MDI mode is active, StatusPane and ToolPane menu items in the Options menu allow you to selectively display or hide the status bar or tool bar. A check next to the menu item indicates that the feature is active. Clicking on the menu item selects the opposite state. Only applications using the ViewManager compatibility with ApplicationWindow will be encapsulated in the MDIFrame window. In particular, create the top pane using: self topPaneClass This uses MDIChild rather than TopPane.

Visual Smalltalk Enterprise Language Reference 441 CHAPTER 22 Multiple Document Interface (MDI) Programming Interface MDI comprises the following classes: • MDIChild • MDIClient • MDIFrame •MDIMenu • MDITranscript • MDISystem • MDIViewManager An MDI application must first create an MDIFrame window. The MDIFrame window is the main window of your application. It encapsulates all the documents of your application (MDIChild). Both MDIFrame and MDIChild classes are subclasses of TopPane. Their protocol is fully compatible with their superclass TopPane. An MDI application class should be under MDIViewManager, which is itself a subclass of ViewManager. The MDI classes use the ViewManager model (event-driven, multiple views on the same model, clear separation between the GUI and the application). Creating an MDIFrame Window The creation of an MDIFrame window is usually accomplished by sending the message open to a new instance of the MDIViewManager subclass. The window opening method initializes the label for the MDIFrame window and registers events such as: mdiMenuBarBuilt menuBarBuilt The MDIClient subpane (MDIClient subpane is the client window of the MDIFrame window) is automatically created by the MDIFrame class and shouldn’t be created by the MDIViewManager subclass.

442 Visual Smalltalk Enterprise Language Reference Creating an MDIChild

Creating an MDIChild Since an MDIChild window is created in the same way as TopPane window, all existing ViewManager subclasses can be used in an MDI application without modifying their code. MDIChild replaces the functionality of TopPane for an MDI application. The following example creates an MDIChild window: self addView:( MDIChild new frame: self frame; owner: self; label: 'Example Child 1'). The only major difference between creating an MDIChild window and a TopPane window is that the frame must be specified for the MDIChild window. The MDIChild class is responsible for creating MDI documents and managing its subpanes. It responds to the system MDI messages and allows applications to set event hooks. The following are the MDIChild instance methods, class methods, and supported events. Instance Methods closeView Close the receiver and all its children. disableSystemMenuItemClose Disable the receiver’s Close system menu item. frame Answer the receiver’s frame. frame: aFrame Set the receiver’s frame to aFrame. frameRectangle Answer the receiver’s frame area as a rectangle. isMDIChild Answer true if receiver is an instance of the class MDIChild; otherwise answer false. label: aString Set the receiver's label without the Visual Smalltalk prefix to aString.

Visual Smalltalk Enterprise Language Reference 443 CHAPTER 22 Multiple Document Interface (MDI)

Class Methods constructEventsTriggered Answer the set of events that MDIChild instances can notify their owners about. Supported Events keyToggled Notify the owner that one of the toggle keys (NumLockKey, InsertKey, CapitalKey) has been pressed. MDIFrame Class The MDIFrame class is responsible for creating the MDI frame window and managing its subpanes. It responds to the system MDI messages and allows applications to set event hooks. Typical subpanes of an MDI frame window are MDIClient, StatusPane, and ToolPane. The MDIFrame class creates the MDIClient subpane. The following are the MDIFrame instance methods, class methods, and supported events: Instance Methods activeTextPane Answer the subpane of the active MDIChild that has the input focus. checkItem: itemName forAllMDIChildMenus: menuName Check the itemName of the menuName. This menu item will be checked for all MDI documents. close The receiver is being closed. Answer nil if one of the receiver’s documents has not been closed. disableItem: itemName forAllMDIChildMenus: menuName Disable the itemName of the menuName. This menu item will be disabled for all MDI documents enableItem: itemName forAllMDIChildMenus: menuName Enable the itemName of the menuName. This menu item will be enabled for all MDI documents. isMDIFrame Answer true if the receiver is an instance of class MDIFrame; otherwise answer false.

444 Visual Smalltalk Enterprise Language Reference MDIFrame Class mdiArrange Arrange the MDI documents. mdiCascade Cascade the MDI documents. mdiChildren Answer a collection of the currently opened MDI documents. mdiCloseAll Close all the MDI documents that are not minimized. mdiGetActive Answer the MDI active document if any, else answer nil. mdiMenuWindow Answer the MDI menu window. It contains the menus at the right side of the menu bar, after the menus specific to the MDI document. mdiMenuWindow: aMenuWindow Answer the MDI menu window. It contains the menus at the right side of the menu bar, after the menus specific to the MDI document. mdiTile Tile the MDI documents. If the Shift key is down, tile vertically. Otherwise, tile horizontally. subPaneWithFocus Answer the SubPane of the receiver that last had the input focus. uncheckItem: itemName forAllMDIChildMenus: menuName Uncheck the itemName of the menuName. This menu item will be unchecked for all the MDI documents. Class Methods constructEventsTriggered Answer the set of events that MDIFrames can notify their owners about. Supported Events mdiMenuBarBuilt Notify the owner that it can create menus. These menus are common to all the MDI documents and come after the menus specific to each documents.

Visual Smalltalk Enterprise Language Reference 445 CHAPTER 22 Multiple Document Interface (MDI)

keyToggled Notify the owner that one of the toggle keys (NumLockKey, InsertKey, CapitalKey) has been pressed. childActivated Notify the owner that an MDI document has been activated. childDeactivated Notify the owner that an MDI document has been deactivated. childClosed Notify the owner that an MDI document has been closed.

NOTE: When the user closes the last MDI document, the owner will not receive a childDeactivate event. The owner will only receive the childClose event.

MDIViewManager Class The owner of an MDIFrame class should be an MDIViewManager class. An MDIViewManager subclass is primarily responsible for: • Creating the MDIFrame • Creating the MDIFrame subpane (ToolBar, StatusBar, if any). • Defining menus common to all MDI documents. • Performing the standard MDI functions to organize the MDI workspace such as Tile, Cascade, and Closeall. • Remembering the current state. The following are the MDIViewManager instance methods: activeTextPane Answer the active text pane of the active MDI document frame. close Close all views. frame Answer the receiver's frame

446 Visual Smalltalk Enterprise Language Reference MDIMenu Class

frame: Set the receiver's frame. mdiArrange Arrange the MDI documents. mdiCascade Cascade the MDI documents. mdiCloseall Close all MDI documents that are not minimized. mdiNewWindow Create a new TextWindow MDI document from the active TextPane. mdiTile Tile the MDI documents. MDIMenu Class This class is used to create the standard MDI window menu for arranging the MDI workspace. Its protocol is fully compatible with its superclass Menu. This class should be used only to create the MDI window menu and only for that purpose. The menus of an MDIFrame window are created using two events: mdiMenuBarBuilt menuBarBuilt The menus created upon receiving these events will be common to all MDI documents. The menuBarBuilt event is used to create the menus that are on the left side of the menu bar. If the owner responds to that event, the MDI frame will not get the standard default Smalltalk File menu. The mdiMenuBarBuilt event is used to create the menus that are on the right side of the menu bar. As a minimum, the frame owner has to create the standard MDI window menu that is used to manage the MDI workspace. For example, the following are instance methods in the MDI Demo:

Visual Smalltalk Enterprise Language Reference 447 CHAPTER 22 Multiple Document Interface (MDI)

open self addView:( self frame: (MDIFrame new owner: self; when: #menuBarBuilt perform: #menu:; when: #mdiMenuBarBuilt perform: #mdiMenu:; labelWithoutPrefix: 'MDI Demo')). menu: anMDIFrame "Private - Build the file menu" anMDIFrame menuWindow addMenu: self fileMenu owner: self. mdiMenu: anMDIFrame "Private - Build the standard MDI window menu" anMDIFrame mdiMenuWindow addMenu: self class mdiMenu owner: self. fileMenu "Private - Answer the receiver's fileMenu" ^Menu new appendItem: '&Green document' selector: #doc1 ; appendItem: '&Yellow document' selector: #doc2; appendSeparator ; appendItem: '&Exit' selector: #exit ; title: '&Demo'. The following is a class method from the demo: mdiMenu ^MDIMenu new appendItem: '&New Window' selector: #mdiNewWindow accelKey: $n accelBits: AfControl; appendItem: '&Cascade Shift+F5' selector: #mdiCascade accelKey: VkF5 accelBits: AfVirtualkey|AfShift ; appendItem: '&Tile Shift+F4' selector: #mdiTile accelKey: VkF4 accelBits: AfVirtualkey|AfShift ; appendItem: 'Arrange &Icons' selector: #mdiArrange; appendItem: 'Close &All' selector: #mdiCloseall; title: '&Window'.

NOTE: For the standard MDI window menu, it is necessary to use the MDIMenu class instead of the normal Menu class to create a menu object. The protocol of the MDIMenu class is fully compatible with its superclass Menu.

448 Visual Smalltalk Enterprise Language Reference MDISystem and MDITranscript Classes

MDISystem and MDITranscript Classes MDISystem and MDITranscript classes are used to encapsulate the Visual Smalltalk development tools in an MDIFrame window. The implementation of MDISystem class demonstrates that all existing ViewManager subclasses can be used in an MDI application without modifying their code. You can use the MDI Mode menu item in the Options menu to switch the Visual Smalltalk environment between the MDI mode and non-MDI mode. Note that this menu item acts as a toggle. The menu item is checked when MDI mode is activated. Selecting this menu item while MDI mode is activated unchecks this menu item and deactivates MDI mode.

Visual Smalltalk Enterprise Language Reference 449

CHAPTER Microsoft Windows 23 Interfaces Overview Visual Smalltalk provides access to a large number of Microsoft Windows (Win32) features by “wrapping” these features. Some of these, such as Windows controls and OLE, have been described throughout this manual. In the current chapter we describe in the Smalltalk access of a few additional features. It is important to note that the Smalltalk implementations described here wrap the native Win32 implementations of these features, rather than mimicking the features in Smalltalk. Registration Database In Windows 3.1 and Windows NT, the registration database is a systemwide source of information about applications. This information is used to support the integration of applications with Windows File Manager and is used by applications that support Object Linking and Embedding (OLE). In Windows NT, the registration database is also called the Registry. Windows NT stores configuration information in the Registry in a tree format. Usually, users never need to view the Registry directly. If you want to browse the contents, use REGEDIT, a tool provided by Microsoft. For details on class registration, registering filename extensions, shell properties, protocol properties, and querying and deleting database entries, refer to the Microsoft Win32 Software Development Kit for Windows NT Programmer’s Reference and the Microsoft Windows 3.1 Software Development Kit Programmer’s Reference. To install registration database support, select the Registration Database in the Service Manager. If you use the registration database in your application, be sure to bind VREGnnp.SLL to the application.

Visual Smalltalk Enterprise Language Reference 451 CHAPTER 23 Microsoft Windows Interfaces

Using the Registration Database An application should use the registration database to store the following information: • The name of the executable file that is associated with a given filename extension. • The command line to execute when the user opens a file from a Windows shell application such as File Manager or Program Manager. • The command line to execute when the user prints a file from File Manager. • Details about the implementation of OLE if the application is an OLE server. Visual Smalltalk provides a high level interface to the Windows registration database using a protocol similar to the interface for Dictionary. An application can access entries in the registration database using the same protocol, such as at:, at:put:, removeKey:, etc. To access the Windows registration database, create a new instance of RegistrationDatabase using either the new or new: message. The new message For example: RegistrationDatabase new inspect. Opens a DictionaryInspector on the default root RegistrationDatabase new keys. Answers the keys of the default root RegistrationDatabase new values. Answers the values of the default root In addition to its Dictionary-like protocol, the RegistrationDatabase class supports several utility methods that can be used to extract specific pieces of information, or to obtain a reference to a particular “root” of the Registry: RegistrationDatabase classesRoot. Answer the (default) root for all registered classes RegistrationDatabase localMachine. Answer the root for the local machine RegistrationDatabase printHierarchy. Answer a printString of the entire hierarchy RegistrationDatabase oleServers. Answer a list of all registered OLE servers

452 Visual Smalltalk Enterprise Language Reference Messaging API (MAPI)

After installation, try the following examples. Evaluate each example using Show It: RegistrationDatabase printHierarchy. RegistrationDatabase new keys. RegistrationDatabase new values. ( RegistrationDatabase new: 'Package\protocol\StdFileEditing\verb\0' ) value. RegistrationDatabase oleServers. RegistrationDatabase oleServerNames. Evaluate the following using Inspect It: RegistrationDatabase oleServerAssocs. RegistrationDatabase classesRoot. RegistrationDatabase localMachine. Messaging API (MAPI) Visual Smalltalk supports the Windows 95 Common Messaging Calls (CMC) subsystem of the Messaging API (MAPI). The CMC subsystem provides cross-platform (Windows, OS/2, Macintosh, UNIX) portability of messaging services. Installing MAPI Support MAPI requires underlying operating support, which is available for Windows 95 and Windwws NT: • On Windows 95, Microsoft Exchange must be installed • On Windows NT, you must install the MAPI subsystem With the operating system level support installed, install the Visual Smalltalk MAPI support by selecting MAPI Support in the Service Manager. Using MAPI Services Your application starts a mail session when a user logs on, by using a class method in MailSession. If the logon is successful, you return an instance of MailSession.

Visual Smalltalk Enterprise Language Reference 453 CHAPTER 23 Microsoft Windows Interfaces

Once you have a mail session, you can send it messages to create new messages (newMessage), new folders (newFolder:), and access an addressbook (addressBookNamed:). Every message, folder and address book is associated with the session in which it is created. You can query the mail session about its folders, delete folders, and logoff from the session. Mail Folders A mail folder is created by sending the message newFolder: to a mail session. The creation message requires a label for the folder as an argument. To get the inbox send the message inboxFolder to the session. Once you have an instance of a mail folder you can either create a new message in that folder (newMessage) or you can add a message (addMessage:). When adding a message, the message was created by sending newMessage to the mail session. You can query the folder about its name and its messages. You can also delete messages from the folder, and rename the folder. To delete a mail folder, send the message deleteFolder: with the folder instance as the argument to the mail session. Mail Messages You create a mail message by sending newMessage to an instance of either MailSession or MailFolder. You can send, delete, reply, and forward a message. You can query every part that makes up a message (author, recipients, subject line, message body, attachments, etc.). To retrieve all the messages of the session you need to send the message messages to the inbox folder. Mail Address Book To get access to the addressbook of the service provider, send the message addressBookNamed: aString to the mail session instance. aString is used to reference the address book. You can open the address book by sending it open, which opens a dialog listing all the available addressees for the service provider. Once you have selected the receivers and closed the dialog, the selections will be saved in the addressees variable. You can use this result as the input for the addresses of a message. Note that the address book implementation is dependent on the provider. Currently only the Microsoft address book is supported.

454 Visual Smalltalk Enterprise Language Reference Messaging API (MAPI)

MailAddressee and MailAttachment Instances of these classes are used to wrap information about an addressee and an attachment, respectively. A new mail message requires an instance of at least one of these classes. MAPI Support Classes A new pool, MAPIConstants, defines the variables needed for the feature. Support is provided in the following classes. For the protocol provided by these classes, refer to the Visual Smalltalk Enterprise Encyclopedia of Classes. MailAddressBook A MailAddressBook is a control that keeps track of names, addresses, electronic mailing addresses, phone numbers, etc. MailAddressee A MailAddressee is an object that holds information about an addressee for a message, such as the name, electronic address, role (originator, to:, cc:, bcc:), and the type (individual, group, unknown). MailAddressees A MailAddressees object holds information about the different addressee selections from an address book or the different addressees associated with a mail message. MailAttachment A MailAttachment is an object that holds information about an attachment, such as the path to the attachment, the label ortitle of the attachent, and the type of the attachment (binary or text). MailFolder A MailFolder is an object that knows about messages in the personal postoffice. MailMessage A MailMessage is an object that holds information about a message such as author, addressees, subject, message body, attachments, date/time sent, message size, delivery priority. MailSession A MailSession is an object that allows you to start a mail session, end it, verify the user and password and other configurations. The following classes are subclasses of ExternalBuffer.

Visual Smalltalk Enterprise Language Reference 455 CHAPTER 23 Microsoft Windows Interfaces

CMCAttachment A CMCAttachment structure defines a CMC message attachment. The last attachment structure should have the CMC_ATT_LAST_ELEMENT flag in the attachFlags field set. CMCCountedString A CMCCountedString structure supports character sets that allow embedded nulls. The structure contains a counted string and explicitly defines the length of the string. CMCExtension A CMCExtension structure defines a CMC data extension for use by the API functions and data structures of the MAPI CMC implementation. The extension adds parameters to functions or members to data structures. CMCMessage A CMCMessage structure defines a CMC message. CMCMessageSummary A CMCMessageSummary structure defines a CMC message summary. CMCRecipient A CMCRecipient is a structure that defines a message recipient or the message originator. CMCTime A CMCTime structure defines a time value in CMC- compatible form for use in a message. The following class is a subclass of DynamicLinkLibrary. MAPIDLL The MAPIDLL provides the low level interface to the messaging system interface of MAPI (32-bit). Multi-Media API Visual Smalltalk on Windows platforms provides access to multimedia support. This allows you to launch audio and video recording and playback sessions in your Visual Smalltalk application using native operating system resources. Classes providing support for multimedia are all subclasses of MciDevice

456 Visual Smalltalk Enterprise Language Reference Plug-and-Play Awareness

Plug-and-Play Awareness Visual Smalltalk on Windows 95 supports the Plug and Play feature, which means that devices can be dynamically configured without having to restart the system. Windows 95 notifies running Windows applications, including Visual Smalltalk, that the configuration has changed. Visual Smalltalk then updates itself accordingly. Handling Plug and Play is handled within Visual Smalltalk, so there is no additional work required by your application.

Visual Smalltalk Enterprise Language Reference 457

Appendix Visual Smalltalk A Syntax Summary How Syntax is Specified The formal syntax specification is presented using the Extended Backus Naur Formalism (EBNF) (Programming in Modula-2 by Niklaus Wirth, Springer-Verlag, 1982). EBNF is used here in order to precisely and concisely specify the syntax. What follows is a specification of EBNF syntax in EBNF. The syntax rules are: syntax = {rule} rule = identifier “ = ” expression “ . ”. expression = term { “ | ” term }. term = factor { factor}. factor = identifier | string | “ ( ” expression “ ) ” | “ [ ” expression “ ] ” | “ { ” expression “ } ”. An EBNF specification is a sequence of syntax rules. The right- hand side of each rule defines syntax in terms of other rule names and terminal symbols of the language. Parentheses, ( and ), group alternative terms. The vertical bar, |, separates alternative terms. Brackets, [ and ], identify optional expressions. Braces, { and }, identify expressions which may occur zero or more times. A string is written as a character sequence enclosed by double quotes (“ ”) and identifies terminal symbols of the defined language. An identifier is a sequence of letters and digits beginning with a letter. The following is an example in which possible meals are defined with a sequence of EBNF rules. appetizer = “ artichoke ” | “ oysters ”. dessert = “ ice cream ” | fruit. fruit = “ apple ” | “ orange ” | “ pear ”. meat = “ beef ” | “ lamb ” | “ fish ”. vegetable = “ broccoli ” | “ carrots ” | “ peas ”. meal = [ appetizer ] meat ( “potatoes ” | “ rice ” ) { vegetable } [dessert]. Examples of meals defined by these rules are the following:

Visual Smalltalk Enterprise Language Reference 459 Appendix A

beef potatoes artichoke fish rice peas broccoli ice cream lamb rice carrots carrots carrots peas broccoli pear oysters beef rice orange Smalltalk Syntax The following is an EBNF syntax specification for Visual Smalltalk and a cross-reference index to the syntax. Each line in the syntax specification begins with a number which is used to identify the line in the cross-reference. The cross-reference shows where each rule name is defined (line number preceded by minus sign) and used. 1. method = messagePattern [ temporaries ] [ primitiveNumber ] [ apiCall ] expressionSeries [ “.” ]. 2. messagePattern = unarySelector | binarySelector variableName | keyword variableName { keyword variableName }. 3. primitiveNumber = “<” “primitive:” number “>”. 4. apiCall = “<“ ( “api” | “c” | “c16” | “pascal” | “pascal16” | “som” | “ole” ) “:” { identifier } “>”. 5. temporaries = “|” {variableName} “|”. 6. expressionSeries = expression { “.” [ expression ] } [ “.” “^” expression [ “.” ] ] ] | [ “^” expression [ “.” ] ]. 7. expression = { variableName “:=” } messageExpression { “;” cascadeMessage }. 8. messageExpression = unaryExpression | binaryExpression | keywordExpression. 9. unaryExpression = primary { unarySelector }. 10. primary = variableName | literal | block | “(” expression “)”. 11. block = “[” [ “:” variableName { “:” variableName } “|” ] [ temporaries ] expressionSeries “]”. 12. binaryExpression = unaryExpression binaryMessage { binaryMessage } . 13. binaryMessage = binarySelector unaryExpression. 14. keywordExpression = ( unaryExpression | binaryExpression ) keywordMessage { keywordMessage }.

460 Visual Smalltalk Enterprise Language Reference Smalltalk Syntax

15. keywordMessage = keyword ( unaryExpression | binaryExpression ). 16. cascadeMessage = unarySelector | binaryMessage | keywordMessage. Scanner Rules: 17. literal = number | string | characterConstant | “#” ( identifier | binarySelector | keyword { keyword } | string | array ). 18. keyword = identifier “:”. 19. variableName = identifier. 20. unarySelector = identifier. 21. binarySelector = “-” | { selectorCharacter | “-” } selectorCharacter. 22. array = “(” { literal | nil | true| false } “)”. 23. number = [ “-” ] ( digits “r” bigDigits | digits [ “.” digits ] [ “s” digits ] | digits “.” digits ( “e” | “d” | “q” ) [ “-” ] digits ). 24. digits = digit { digit }. 25. bigDigits = bigDigit { bigDigit }. 26. bigDigit = digit | capitalLetter. 27. stringCharacter = { character | “ ' ' ” | “ " ” }. 28. string = “ ' ” { stringCharacter } “ ' ”. 29. characterConstant = “$” (character | “ ' ” | “ " ” ). 30. comment = “ " ” { character | “ ' ” } “ " ”. 31. identifier = ( letter | “_” ) { letter | digit | “_” }. 32. character = selectorCharacter | letter | digit | “[” | “]” | “{” | “}” | “(” | “)” | “^” | “;” | “$” | “#” | “:” | “.” | “_” | “`”. 33. selectorCharacter = “,” | “+” | “/” | “\” | “*” | “~” | “-” | “<” | “>” | “=” | “@” | “%” | “|” | “&” | “?” | “!”. 34. letter = capitalLetter | nativeLanguageLetter |“a” | “b” | “c” | “d” | “e” | “f” | “g” | “h” | “i” | “j” | “k” | “l” | “m” | “n” | “o” | “p” | “q” | “r” | “s” | “t” | “u” |“v ” | “w” | “x” | “y” | “z”.

Visual Smalltalk Enterprise Language Reference 461 Appendix A

35. capitalLetter = doubleByteCharacter | nativeLanguageCapitalLetter | “A” | “B” | “C” | “D” | “E” | “F” | “G” | “H” | “I” | “J” | “K” | “L” | “M” | “N” | “O” | “P” | “Q” | “R” | “S” | “T” | “U” | “V” | “W” | “X” | “Y” | “Z” 36. digit = “0” | “1” | “2” | “3” | “4” | “5” | “6” | “7” | “8” | “9” 37. nativeLanguageCapitalLetter = < character designated as capital letter by the host system >. 38. nativeLanguageLetter = < character designated as alphabetic by the host system excluding nativeLanguageCapitalLetter >. 39. doubleByteCharacter = < character with value greater than 255 >. Visual Smalltalk Grammar Cross Reference array 17 -22 bigDigit 25 -25 bigDigits 23 -25 binaryExpression 8 -12 14 15 binaryMessage 12 -13 16 binarySelector 2 13 17 -21 block 10 -11 capitalLetter 26 34 -35 cascadeMessage 7 -16 character 27 29 30 -32 characterConstant 17 22 -29 comment -30 digit 24263132-36 digits 23 -24 doubleByteCharacter 35 -39 expression 6 -7 10 expressionSeries 1 -6 11 identifier 17 18 19 20 -31 keyword 2 15 17 -18 keywordExpression 8 -14 keywordMessage 14 -15 16 letter 31 32 -34 literal 10 -17 messageExpression 7 -8 messagePattern 1 -2 method -1 nativeLanguageCapitalLetter 35 -37 nativeLanguageLetter 34 -38 number 3 17 22 -23 primary 9 -10 primitive 3

462 Visual Smalltalk Enterprise Language Reference Smalltalk Syntax primitiveNumber 1 -3 selectorCharacter 21 32 -33 string 17 22 -28 stringCharacter 22 -27 -28 temporaries 1 -5 unaryExpression 8 -9 12 13 14 15 unarySelector 2 9 16 -20 variableName 2 5 7 10 11 -19

Visual Smalltalk Enterprise Language Reference 463

Appendix Programming B Guidelines Introduction A goal for someone using any programming language is to create code that is readable, understandable, concise and efficient. A good, consistent programming style should increase productivity, reduce the number of errors and improve reliability and maintainability. Because most of the cost of software development is in the continued maintenance of the code, developing coding guidelines plays a very important role in the software development cycle. The extra effort spent in writing aesthetically pleasing and elegant Smalltalk code will pay for itself many times over during the life of the software. In addition to “pretty printed” coding styles, there are more fundamental programming techniques that will help ensure that a program will be reusable and extensible for future development. This appendix recommends some guidelines for Smalltalk programming practices. There are two main sections: the first describes style and formatting guidelines, the second recommends general programming practices that can lead to higher-quality, more-reusable code. Programming guidelines are not universal rules. Individual items may or may not apply in specific circumstances. These guidelines come from the accumulated experience of numerous Smalltalk programmers both within and outside of Cincom. Programming style and guidelines evolve as programmers gain experience with larger and more varied systems. Cincom welcomes your suggestions for improving and expanding these guidelines.

Visual Smalltalk Enterprise Language Reference 465 Appendix B Style Guidelines

Methods The method template that Visual Smalltalk supplies is an excellent starting point for discussing method formatting. The format is as follows: messagePattern "comment" | temporaries | statements With a slight modification, this general form becomes: messagePattern "comment" | temporaries | statements The addition of the blank line between the comment and the code distinguishes them and makes the extra indentation of the comment unnecessary. Method Names Method names should be descriptive of what the methods do. Avoid abbreviations unless they are standardized within the company or are widely used acronyms. Be specific when naming the method. Method names should begin with lowercase letters. If the name is a compound word, start the second word and all following words with a capital letter. In multiple keyword methods, the first letter of each keyword should start with a lowercase letter (e.g., copyFrom:to:). Choosing the Method Name Be consistent in naming methods. Look for patterns in the image and follow them where appropriate. For example, in the collection classes, there are a number of methods for converting from one type of collection to another. The pattern that Visual Smalltalk follows for naming conversion methods is asType, where Type is the name of the class to which the receiver is to be converted (e.g., asOrderedCollection or asSortedCollection). If you add a new method to convert a collection to a SpecialCollection, call it asSpecialCollection instead of convertToSpecialCollection.

466 Visual Smalltalk Enterprise Language Reference Style Guidelines

Other methods that follow a pattern are those that return a Boolean value. You might call such a method isNil or isInteger, or isBlue or isSameColorAs:. Methods with Arguments Visual Smalltalk provides two kinds of methods that take arguments. A binary method takes a single argument. A keyword method has one or more arguments. Following is the method template for a keyword method. Note that the square brackets denote optional additional keyword/argument pairs. For readability, each keyword/argument pair is on a separate line. keyword1: argument1Name [keyword2: argument2Name ...] "comment" ... There are two important pieces of information to convey when naming a method with arguments: • What the method does • The type of object or role each of its arguments represents Here is an example of a binary method from Number @ aNumber "Answer a point with the receiver as the x-coordinate and as the y-coordinate."

^Point new x: self; y: aNumber and a keyword method from Magnitude. between: min and: max "Answer true if the receiver is greater than or equal to and less than or equal to ; else answer false."

^min <= self and: [self <= max] The name of the argument in the first example clearly indicates the required type of object that the method expects. The second example describes only the roles that the parameters play, not their types.

Visual Smalltalk Enterprise Language Reference 467 Appendix B

Variable Names Choose variable names that are meaningful within the context of the class or method in which they are defined. Variable names should be clear, concise and unambiguous. Avoid abbreviating a variable name unless the abbreviation is standardized within the company or is a widely used acronym. Instance Variable Names Consider a class that describes fruit. It might have instance variables that describe the weight of the fruit, its degree of ripeness, its color, and so on. Some reasonable variable names for the class could be: “weightInOunces,” “ripeness,” and “color.” Names such as “wt,” “ripe,” or “clr” are unclear and ambiguous. Does “wt” stand for weight or whiteness? While “ripe” is not an abbreviation, it implies a boolean (true/false) value. The name “clr” could mean color, or clear, or any number of things. Using clear and concise variable names makes your code easier to read and understand. Temporary Variable Names Select temporary variable names with the same or greater care as instance variable names. Avoid short meaningless names like i, j, and k. Again, names should be meaningful. Block Argument Names The argument names for blocks tend to be words like each or index. Make the name more descriptive. This is especially important when loops are nested. ... someClass allSubclasses do: [:eachSubclass | eachSubclass selectors do: [:eachSelector | methodNameList add: eachSelector]] Capitalization A general rule for capitalizing variable names is to capitalize shared variables and to not capitalize private variables. When an identifier or message selector comprises more than one word,

468 Visual Smalltalk Enterprise Language Reference Style Guidelines

concatenate and capitalize all words but the first. It is not customary to begin selectors or keywords with capital letters unless they are proper names or standard abbreviations. The following table illustrates naming conventions for variables.

Item Begins with global variable name upper-case class name upper-case class variable name upper-case pool dictionary variable name upper-case class instance variable name lower-case instance variable name lower-case temporary variable name lower-case method name lower-case argument name lower-case

Blank Lines Use blank lines sparingly in Smalltalk. In most procedural languages, you must use blank lines liberally to make the code readable. The methods should be small enough that numerous blank lines are not necessary. Because the Visual Smalltalk browser typically shows less than a dozen lines, and most methods fit into that space completely, the only blank line in a typical method should be between the comment and the body of the method. Leaving a blank line may confuse someone browsing the method if that blank line shows up as the last line in the text view of the browser. They may not realize that there is code below the blank line that is not showing. However, do not sacrifice readability at the expense of eliminating white space. Brackets and Parentheses Visual Smalltalk provides an easy way to check for matching parentheses and brackets; simply double-click on the opening or closing delimiter.

Visual Smalltalk Enterprise Language Reference 469 Appendix B

Brackets It is not as useful to use dangling brackets in Smalltalk as it is in procedural languages where a generic text editor is the primary code entry tool. The following example, although common in C, shows a procedural style not generally used in Smalltalk. It uses four extra lines of browser text space. Smalltalk is not as dense as C, so there is no need to force insertion of excessive white space. Boolean expression ifTrue: [ "Wasted white space" a line a line ] ifFalse: [ a line a line ] You can generally code short statements on one line each. booleanExpression ifTrue: [one line] ifFalse: [one line] Format longer conditionals as follows: Boolean expression ifTrue: [ a line ... a line ] ifFalse: [ a line ... a line ] . Programmers generally format enumeration methods (loops) in one of the following styles: someCollection do: [ :eachElement | statement. ... statement ] .

470 Visual Smalltalk Enterprise Language Reference Style Guidelines

someCollection do: [ :eachElement | statement. ... statement ] . Parentheses Avoid using totally extraneous parentheses such as: maxAllowed := (size * 2). offset := (maxAllowed) Use parentheses to clarify, but not clutter, your code. For example: frame width: (newFrame width * 4) is equivalent to, but may be slightly more readable than: frame width: newFrame width * 4 Formatting and Indentation Control Flow Normally, methods do not need complex internal control flows. Keep them short, simple and single purposed. When methods do have conditions and/or loops, the visual structure of the method should reflect the logical structure of the flow of control. Do not indent simple groups of expressions arbitrarily. Instead, use indentation to illustrate the control flow so the bounds of the controlled block are clearly visible. If you implement nested control flows, always match the amount of indentation to the level of nesting. We have shown specific examples for ifTrue:ifFalse, do:. Use those examples as a general guideline. Long Keywords Indent long keyword messages to improve readability and avoid wrapping lines, as in: aTree := self value: 'root node' leftNode: nil rightNode: (self value: 'right node' leftNode: nil rightNode: nil))

Visual Smalltalk Enterprise Language Reference 471 Appendix B

Cascaded Messages Cascaded messages should normally be indented, one message per line, below the receiver. aStream nextPutAll: 'The result is '; nextPutAll: result printString; space; nextPutAll: result units printString One exception is for short, simple cascades like the following: aStream cr; nextPutAll: answer printString

Comments Class Comments Write comments that describe in detail each of your classes. Class comments may be either public or private. The target audience for public comments are clients who are developing classes that will collaborate with your class. The comments comprise: • A brief description of the class • Special usage considerations (if any) Private comments describe implementation details about the components and the internal behavior of the class. The target audience for private comments are developers and maintainers of the class. These comments consist of: • A description for each instance, class and class instance variable • Descriptions of special algorithms (if any) • Subclasses responsibilities (if the class is intended to be an abstract superclass) Your organization might also adopt local standards for the class comment. For example, a class comment might include the name of the original author of the class, the current maintainer, revision history, etc. You can implement two class methods for each class; one for public and the other for private comments. The methods store the comment text and have no executable code. Use all capital letters

472 Visual Smalltalk Enterprise Language Reference Coding Guidelines

for the method names to differentiate them from any of the “real” methods defined for the class, e.g., COMMENT and PRIVATE- COMMENT.

NOTE: Visual Smalltalk Enterprise includes a facility in the browser to support class comments. In this environment, the preferred way to comment a class and its variables is through the toolset.

Method Comments Generally, Smalltalk methods should be short enough that they do not need comments among the source code. Almost all comments in a method should occur before the body of the code. Be sure that the comment agrees with the code. Use embedded comments only when you need to describe any unusual assumptions or conventions. There are three types of comments you should include with each method. • The first is a required comment which describes, from the clients (public) point of view, what the method does and what it returns. • The second is optional and describes any implementation details (private) which need clarification. • The third is optional and generally only makes sense in class methods. It is a sample invocation that you can execute to demonstrate the code. Place this comment on a line by itself so a programmer can easily find it (see example in the section Executable Comments in this appendix). Accessing methods for variables should contain descriptive comments about the variables themselves. These comments are more fully discussed in the section Accessing Methods. Coding Guidelines

Class methods Class methods generally fall into two main groups: instance creation and general queries. General queries request information that the class encapsulates, such as class variables, documentation or instance management. All of the criteria for good programming practices apply equally to class methods as to instance methods.

Visual Smalltalk Enterprise Language Reference 473 Appendix B

Executable Comments A convenient addition to class methods, where appropriate, is to add another comment line that you can use to invoke the method. For example, the BiographyNotebook class might have an open method as follows. open "Create a new notebook and open it with the default frame." "BiographyNotebook open"

self openOn: self sampleBiography Someone exploring the class can then highlight the text of the second comment, select Do It or Show It from the text menu and see the result. This is very convenient. In addition, it is an indication of how to use the code. Examples In the same spirit, you can use additional example methods to indicate how you can or should use a class. For example, a class called BinaryTree might declare some example methods like the following. example1 "Create a simple BinaryTree. This shows construction protocols, size queries, and printing." "BinaryTree example1" | aTree | aTree := self value: 'root node' leftNode: nil rightNode: (self value: 'right node' leftNode: nil rightNode: nil)). Transcript cr; show: aTree printString. Transcript cr; show: aTree size printString. ^aTree Since example code is not required for your system to run properly, consider providing the example code in a separate file- in file so it can be loaded into an image only when desired.

474 Visual Smalltalk Enterprise Language Reference Coding Guidelines

Testing You can add test methods to classes. In the same way that example methods show you how to use a class, test methods serve as a test suite that you can run after each modification of the class.

Modifying Existing System Methods System methods are the methods supplied by Visual Smalltalk as part of the standard image. At times you may consider changing some of these methods. In two words: do not. Unless it is absolutely necessary, you should not modify system methods. Even if you check senders of a method, you only see those classes currently loaded into the image. Another application not currently loaded into the image may depend on the particular characteristic of the method you wish to change. Another reason for not changing system code is that it would be difficult to maintain the modification. There is no guarantee that the method will remain the same from release to release. You would have to remember to install it every time you change images and make sure it still works with your version of Visual Smalltalk. Better solutions include: • Create an alternative method with a similar but distinguishable selector • Subclass the system class and override the method in the subclass If a system modification seems like the only solution, check with your local Visual Smalltalk system administrator for other solutions before modifying system code. Extending System Classes Occasionally you may find it necessary to add methods to system classes. You should do this carefully. A good initial strategy is to create a subclass of a system class and add the new methods there. If you can leave the subclass in the image, it will give you the most isolation against new releases of the system code. Your modified methods will be immediately obvious and you can check them for compatibility with the new system.

Visual Smalltalk Enterprise Language Reference 475 Appendix B

If it is not practical to leave the methods in the subclass, you should migrate them to the system class only after you have thoroughly tested them. Keep a record of the changes you have made to the system classes so you can include them in your next application release.

NOTE: If you are using Visual Smalltalk Enterprise, you can add the method as an extension to the class in a package defined in that application rather than in the system package.

Variable Usage Constant Usage Access constants by sending messages to appropriate classes or instances. Implement class or instance methods that return the desired constant value. Do not embed constants in your code. If you ever need to change the value of a constant, you need only change it in one place instead of searching throughout your code for usage. Also, if you intend to subclass, you can return different constant values for each subclass level, if desired. Following is an example of a method that returns a constant value. pi "Answer the constant value of pi."

^3.14159 Attributes vs. Variable Accessors Define public interfaces to classes in terms of attributes, not variable accessors. An attribute is a value that can be publicly set for an object and later retrieved. Typically you will do this with a pair of related messages. For example: aThing color: Color red. aThing color "returns the color of the receiver" An attribute is not the same thing as a variable. We often use variables to implement the storage of attributes. Sometimes, other techniques are more appropriate. For example, a class with many attributes that seldom change might use a dictionary to record their values rather than create a variable for each one. You would only add an entry into the dictionary when you set the value of an attribute.

476 Visual Smalltalk Enterprise Language Reference Coding Guidelines

When implementing methods within a class, consider whether a method needs to access an attribute (the public abstraction) or the variable (the private implementation of the attribute). Whenever possible, use the attribute for the public interface. For example, a manufacturing order might want to say: aWagon color: Color red. Internally the Wagon class might implement this as: color: aColor "Set the color with which to paint the receiver. is the value of a paint mixture. Valid values are: Color red, Color green and Color blue."

self paintColor: aColor. self issuePaintOrder and color "Answer the name of the color that the receiver is painted."

^self paintColor Using the attribute accessor as a public interface hides the implementation details of changing the value of paintColor. Comment this accessor with text that describes what the method does and what it returns from the clients (public) point of view. Accessing Methods You should implement only one method in each class that directly sets, and only one method that directly retrieves each variable. We call these accessing methods. For example, if a class has an instance variable called paintColor, define two access methods: paintColor "Private. Answers the color of the paint that the receiver is painted. The paintColor instance variable stores a representation of the color of the paint. It should contain one of the following values: Color red, Color green, Color blue."

Visual Smalltalk Enterprise Language Reference 477 Appendix B

^paintColor paintColor: aColor "Private. Sets the color of the paint that the receiver is painted to . The paintColor instance variable stores a representation of the color of the paint. It should contain one of the following values: Color red, Color green, Color blue."

paintColor := aColor Always use accessing methods to reference variables. Using a message-send with the appropriate accessing protocol is slightly less efficient than accessing variables directly, but it is safer and more flexible. • It encapsulates the storage information even within the defining class. If you subsequently store the data in a different format, you need only change the accessing method itself. • If you subclass a class with defined variables, you can customize the accessing methods for each of the subclasses, thus overriding the default accessors. • You can add lazy initialization, if needed (see the Lazy Initialization section). • You can add a self halt to the accessing method to create a data breakpoint. Also, you can check for error bounds to make the data breakpoints conditional. For example, you could write the paintColor: accessor described above as: paintColor: aColor "Private. Sets the color of the paint that the receiver is painted to . The paintColor instance variable stores a representation of the color of the paint. It should contain one of the following values: Color red, Color green, Color blue."

((Array with: Color red with: Color green with: Color blue) includes: aColor) ifTrue: [paintColor := aColor] ifFalse: [self invalidColor: aColor] Accessing methods that should be private method category and be marked “Private” in the method comment.

478 Visual Smalltalk Enterprise Language Reference Coding Guidelines

The comments in accessing methods are among the most important in the system and are probably the hardest to write. Such accessing method comments as “Set the variable.” or “Return the variable.” are meaningless. In accessing methods, the comment should describe the variable rather than the method itself. Good information for this type of comment includes: • What the variable is (e.g., the color of the car, not the color used to display the car on the screen) • How it is used (e.g., used to generate a paint shop order for manufacturing) • What variable’s type is (e.g., Point, Number, Symbol, ...) • Any range restriction (e.g., must be a number between 1 and 10) • Any other information that would help someone understand the use of the data.

NOTE: Visual Smalltalk Enterprise includes a facility in the browser to support variable comments. In this environment, you could minimize the comment in each accessor by using the toolset to describe the variable.

All instance, class, and class instance variables should have accessor methods. Instance Variable Usage Instance variables encapsulate information that is unique to each instance, not shared. Each instance has its own copy of each instance variable. A subclass will inherit the instance variable names of its superclass, but their initial value will always be nil; each instance must initialize its own instance variables. Class Variable Usage The scope of a class variable includes the defining class, all instances of that class, all subclasses and all instances of those subclasses. It is important to remember that there is only one copy of a class variable. If a subclass modifies a class variable inherited from a superclass, the superclass will access the modified value as well. Use class variables to store information that you want to share between all instances of a class and its subclasses. For example, they might hold default creation parameters that could be copied to instance variables when you instantiate a class.

Visual Smalltalk Enterprise Language Reference 479 Appendix B

Class variables are static: their values are saved when you save your image. Any object that a class variable references will not be garbage collected. One use for class variables might be to hold distinguished instances of their class or of a related class. For instance, a Spreadsheet class might store a reference to the currently open spreadsheet in a class variable. (Note that this would limit you to having only one spreadsheet open at any one time). current "Answer the currently open spreadsheet." ^CurrentSheet If you choose to do this, it is important to have a way of clearing that variable after you finish using its value. In the spreadsheet example, you should create a method that sets the current spreadsheet to nil when you close the spreadsheet. close "Close the currently open spreadsheet." CurrentSheet close. self resetCurrent resetCurrent "Reset the value of the currently open spreadsheet." CurrentSheet := nil If you do not reset the value, the instance of the spreadsheet will be saved with the image. This could consume excessive disk space. Even worse than this, it could cause your code to fail the next time you start your image and then try to send a message to the current spreadsheet (other than perhaps open). It is sometimes necessary to remove all instances of a class for certain types of class modifications. To facilitate this, you should provide some way of clearing class variables for any class that uses the variables to store application objects. Class Instance Variable Usage Class instance variables are similar to instance variables, except that their scope is limited to the class. Subclasses inherit the variable slot, but they can assign their own unique value to the variable without modifying the superclass value. If a subclass does not initialize an inherited class instance variable, its value will be nil, just as with regular instance variables.

480 Visual Smalltalk Enterprise Language Reference Coding Guidelines

We recommend using class instance variables instead of class variables because they are not shared among all the subclasses. This allows you to customize the values for each subclass. Pool Variable Usage Use pool variables to share objects between different classes. The scope of pool variables includes any class that explicitly includes the pool and all of the instances of those classes. Subclasses in Visual Smalltalk do not inherit pools. Traditionally, programmers use pool variables to store collections of constants. For an example of pool usage, inspect the dictionary CharacterConstants. Pool variables are static; their values are saved when you save your image. Any object that is referenced by a pool variable will not be garbage collected. You must explicitly create pools before you can define the classes that use them in the image. If you are using file-in files to store your code, file-in the file defining the pool before you file in the actual code.

NOTE: In Visual Smalltalk Enterprise, use the initialization facilities to create the pool within a package.

Global Variables Usage Avoid using global variables! The only time you should use a global is if you really need to access the object from any other object. Transcript is an example of a reasonable global. If you must use a global, always check whether a variable by the chosen name exists before doing the first assignment. Type the variable name into a workspace and evaluate the variable using Show It. This will show you if it is already in use, and should prevent you from inadvertently destroying the existing variable’s contents. This is a good precaution when choosing class names as well. As an alternative to a global, consider using either a class variable or class instance variable with accessing methods, or a pool dictionary. Either of these options are less dangerous to use than a global variable.

Visual Smalltalk Enterprise Language Reference 481 Appendix B

If you must use global variables in an application, set them up in the initialization code for the application. Loading the application into a clean image will then recreate its initial state. Likewise, you should implement a way to remove the global variables from the image when you remove the application. Consider a spreadsheet application that comprises dozens of new classes. It might define several parameters that would be useful in a number of different classes within the spreadsheet code. Assume these parameters are backgroundColor, currentSheet and userPreferences. Rather than create global variables for the parameters, create an application class called Spreadsheet that defines class variables or class instance variables with the appropriate accessing methods. While it is true that any object in the image can send a class message to any class, it is at least clear that the Spreadsheet class method backgroundColor: sets the color for spreadsheets, not the color for any object in the image. It is much less obvious to define a global called BackgroundColor that could apply towards any object in the image. In addition to providing support for application-wide variables, a class like Spreadsheet is a good place to implement application initialization and cleanup code. Variable Reuse You might not always reference an inherited instance variable in a subclass. When this happens, there is a temptation to reuse the existing slot for a different purpose. Resist the temptation! Inconsistent usage between superclass and subclasses would be confusing for future maintainers of the code.

Nested Conditionals As a rule, you should not deeply nest conditional statements. One or two levels of ifTrue:ifFalse: should be adequate for most methods. If you find yourself wanting a case statement, reconsider the problem decomposition. In Smalltalk, you can often replace these conditionals by effectively using polymorphism, where different classes handle the same message in their own unique way. To illustrate this principle, we will introduce a partial implementation of the Paper/Scissors/Stone game. First is a sample of procedural decomposition in case statement-like constructs.

482 Visual Smalltalk Enterprise Language Reference Coding Guidelines

In Stone: compareWith: anObject "Compare the receiver with ." (anObject isKindOf: Paper) ifTrue: [self lose] ifFalse: [(anObject isKindOf: Scissors) ifTrue: [self win] ifFalse: [self tie]] In Paper: compareWith: anObject "Compare the receiver with ." (anObject isKindOf: Stone) ifTrue: [self win] ifFalse: [(anObject isKindOf: Scissors) ifTrue: [self lose] ifFalse: [self tie]] In Scissors: compareWith: anObject "Compare the receiver with ." (anObject isKindOf: Paper) ifTrue: [self win] ifFalse: [(anObject isKindOf: Stone) ifTrue: [self lose] ifFalse: [self tie]] Now consider a more object-oriented, polymorphic solution. Each class defines identically named methods with their own unique behavior. In Stone: compareWith: anObject "Compare the receiver with ." ^anObject compareWithStone compareWithStone "Compare the receiver with a stone." ^self tie

Visual Smalltalk Enterprise Language Reference 483 Appendix B

compareWithPaper "Compare the receiver with paper." ^self lose compareWithScissors "Compare the receiver with scissors." ^self win In Paper: compareWith: anObject "Compare the receiver with ." ^anObject compareWithPaper compareWithStone "Compare the receiver with a stone." ^self win compareWithPaper "Compare the receiver with paper." ^self tie compareWithScissors "Compare the receiver with scissors." ^self lose In Scissors: compareWith: anObject "Compare the receiver with ." ^anObject compareWithScissors compareWithStone "Compare the receiver with a stone." ^self lose compareWithPaper "Compare the receiver with paper." ^self win compareWithScissors "Compare the receiver with scissors." ^self tie Not only have we eliminated the nested conditionals, we have also provided a framework for easily extending the types of objects in the game without having to modify existing methods.

484 Visual Smalltalk Enterprise Language Reference Coding Guidelines

Explicit Class References Using self Avoid using explicit class references. When an instance method needs to send a message to its class, it should use self class rather than its explicit class name. When a class method needs to send itself a message, it should just use self. For example, if you wish to define an instance method for the Apple class that returns a new instance of Apple with the same color as the receiver, use: replicate "Answer a new apple with the same color as the receiver."

^self class new color: self color instead of: replicate "Answer a new apple with the same color as the receiver."

^Apple new color: self color This second method, if sent to an instance of a subclass of Apple, would return an instance of the wrong class. References to Other Classes Sometimes you cannot avoid references to other classes. In these cases, you should centralize the references in a single method so subclasses can easily override them. Suppose that in our produce example there are several methods that need to create or refer to containers for various types of fruit. In Fruit: shippingWeight "Answer the shipping weight of a standard container of fruit."

^self fruitContainerClass tareWeight + self weight In Apple: fruitContainerClass "Apples are contained in baskets."

^Basket

Visual Smalltalk Enterprise Language Reference 485 Appendix B

In Orange: fruitContainerClass "Oranges are contained in crates."

^Crate This centralization mechanism allows you to reuse the code for future subclasses simply by adding the fruitContainerClass method to each new subclass.

Class Type Checking Do not implement code to check for the type of a class. For example: ripen: aFruit "Set the color of the fruit to its ripe color."

aFruit isKindOf: Apple ifTrue: [aFruit color: Color red] ifFalse: [aFruit class == Banana ifTrue: [aFruit color: Color yellow] ifFalse: [aFruit color: Color black]]. This code has several disadvantages. One is that this kind of checking makes your program slower. A number of difficulties arise for future enhancements. The first is the isKindOf: message. isKindOf: aClass answers true if the receiver is an instance of aClass or an instance of a subclass of aClass. In the above example, a problem would occur if you were to subclass Apple with a class called GoldenDeliciousApple. This code would have the yellow apples ripen to red. Another problem would occur if you were to subclass Banana. Even if the subclass of Banana would ripen yellow, the explicit class test would pass it up and set the ripe color to black. Explicit testing of classes is often a symptom of poor class inheritance decomposition. The only place where explicit class testing is generally proper is in testing the types of arguments for calls to user primitives. In this case, passing in the wrong class of object could cause a system crash. Even in user primitives, however, the testing is usually done by the primitive code (note that this is not universally true, so it is still a good idea to test the arguments anyway).

486 Visual Smalltalk Enterprise Language Reference Coding Guidelines

An alternative to explicit class testing is to use polymorphism to implement the desired behavior. For the above example, you would implement the following methods: ripen: aFruit "Set to its ripened state."

aFruit ripen In Fruit: ripen "Set the color of the receiver to its ripe color."

self color: Color black In Apple: ripen "Set the color of the receiver to its ripe color."

self color: Color red In GoldenDeliciousApple and Banana: ripen "Set the color of the receiver to its ripe color."

self color: Color yellow In addition to eliminating explicit class testing, we have provided a way to add a new class of fruit to the system without modifying existing methods. In the new Plum class: ripen "Set the color of the receiver to its ripe color."

self color: Color purple To ensure that the object to which you are sending the ripen message is actually an instance of a subclass of Fruit, you might also want to implement the following messages: ripen: aFruit "Set to its ripened state."

aFruit isFruit ifTrue: [aFruit ripen] In Fruit:

Visual Smalltalk Enterprise Language Reference 487 Appendix B

isFruit "Answer if the receiver is a fruit. Answer otherwise."

^true In Object: isFruit "Answer if the receiver is a fruit. Answer otherwise."

^false Initialization There are several initialization strategies commonly used in Visual Smalltalk programs. Typically, you should initialize instance variables in instance methods rather than sending multiple messages to the newly created object in a class method. Initialize class variables and class instance variables in class methods. Explicit Initialization In this strategy, it is the responsibility of the clients of a class to explicitly send a message to initialize new objects. The advantages of this strategy are twofold: it is the most efficient in terms of machine cycles and it is obvious where initialization takes place. The disadvantages of the strategy are that it is the most error prone and that the initialization message must be part of the public protocol of the class. If you forget to initialize a variable and the code that accesses it assumes that the value will be non- nil, your code will fail the first time you try to use its value. Lazy Initialization If all instance and class variable accessing is done through accessing methods, then those methods can check to see if the variables have been initialized. This strategy is not as efficient as the explicit initialization strategy, but it ensures that the value of the variable will be set before it is used. To illustrate this strategy, following is a method that accesses a variable that should contain an OrderedCollection. list "Answer the list of objects. If the list has not been

488 Visual Smalltalk Enterprise Language Reference Coding Guidelines

initialized, create and return an empty list."

list == nil ifTrue: [self initializeList]. ^list Automatic Initialization Another common initialization practice is to override the class method new as follows. new

^super new initialize This has the advantage of always creating an initialized instance of the class. Before overriding the method new, check to see what implementation of new the class inherits. If a superclass has already implemented new as ^super new initialize then overriding it again will cause the initialize method to be called again. If initialize has any cumulative effects (e.g., adding something to a collection) this second invocation not only wastes cycles, but can cause bugs as well. Initializing Subclasses When initializing subclasses, initialize only the instance variables defined in the subclass and allow the code in the superclass(es) to initialize their own variables. Consider an example class Wagon with a subclass DeluxeWagon. In Wagon: initialize "Initialize the receiver for standard production configuration."

self color: Color red. self wheelSize: 4 In DeluxeWagon: initialize "Initialize the receivers production configuration."

super initialize. self trimPackage: DecalSet deluxe If you add another instance variable named handle to Wagon, you would simply add code to initialize it in the initialize method defined for the superclass Wagon.

Visual Smalltalk Enterprise Language Reference 489 Appendix B

Sometimes it may be necessary to override an initialization parameter that was set in a superclass method. This is why it is a good idea to always initialize from the superclass method first. For instance, in another version of DeluxeWagon: initialize "Initialize the receivers production configuration."

super initialize. self wheelSize: 5. self trimPackage: DecalSet deluxe

Inappropriate Array Usage Do not create arrays to pass around related items. Instead, define a class to convey a meaningful abstraction of the items. Your code will immediately become more understandable and extensible. Following is an example of this non-recommended practice: dateAndTimeNow "Answer an Array with the date and time now."

^Array with: self today with: Time now If you were to write a client object to use this value to keep track of events, you would have to write code like: now := Date dateAndTime now. "Assume the variable 'then' contains another date/time array." ((now at: 1) >= (then at: 1) and: [(now at: 2) > (then at: 2)]) ifTrue: [oldest := then at: 1] You would have to remember which element is which. You also have to remember the procedure for comparing date/time pairs. A better solution would be to create a new class that represents an associated date and time. TimeStamp might be a reasonable name for such a class. You could then define messages to access its date and time, compare it with another TimeStamp, etc. You could then rewrite the above as: In class Date: dateAndTimeNow

^TimeStamp date: self today time: Time now

490 Visual Smalltalk Enterprise Language Reference Coding Guidelines

In client code: now := Date dateAndTime now. now > then ifTrue: [oldest := then date] Hide Implementation Details Using the Visual Smalltalk browser, internal implementation details of most methods, both public and private, are available for you to use. Don’t Depend on Illicit Knowledge Do not use implementation knowledge that is not documented in public interface specifications. The implementation may change in a way that conforms to the specification but invalidates what you think you know about it. Consider a class that uses a dictionary to store a collection of fruit. The public interface for adding a fruit to the collection might be a message called add:. However, by examining the method, you might see that the actual implementation is at:put:. add: aFruit "Public interface specification: add to fruitBasket."

self fruitBasket at: aFruit name asSymbol put: aFruit A client of this method might be tempted to do something like: grocery fruitBasket at: #apple put: apple Do not do this! The implementer of add: has every right to change the internal representation of the collection to be an instance of a Set, an OrderedCollection or any other collection class. Assuming that the implementer decides to use an OrderedCollection, the add: method would potentially be recorded as: add: aFruit "Public interface specification: add to fruitBasket."

self fruitBasket addLast: aFruit Any client code using the public interface message will still work. Those who have violated the rule, in this instance, will fail.

Visual Smalltalk Enterprise Language Reference 491 Appendix B

Avoid Action at a Distance One warning flag of poor encapsulation is a long chain of messages. For example: self editor window boundingBox lowerRight x: (self editor window boundingBox lowerRight x + 23) Whatever this object is, it not only knows about its editor, but several levels of internal structure of its editor. Perhaps what was intended was: self editor growBy: 23@0 Assuming the first piece of code could ever have worked, what would happen if the structure of the editor changes or if it needed to do some special update when its window changes? In the extreme case, you should address all messages to the nearest neighbor object. Sometimes it is necessary to look one object beyond the nearest neighbor, but acting on the details of objects several times removed is a sure way to get into maintenance problems. Separate Details from Logical Steps Avoid writing large methods. Large methods often are an indicator of a procedural solution rather than an object-oriented solution involving collaborating objects. The major problem with large methods becomes most obvious when you try to create and maintain the methods in subclasses. If a subclass needs to change one line of a 100-line method, it needs to copy (and hence assume responsibility) for 99 other lines of code as well. If any of the copied lines of code needs to be changed in a superclass, e.g., to fix a bug, it is often missed in the subclass copy. The exposure to this problem is much smaller if the original 100-line method had been broken up into 10 10-line methods, only one of which was overridden by the subclass. If you find yourself writing a large method, see if you can transform that method into a simpler method with a sequence of logical steps that invoke smaller functional methods. This simpler method will be easier to read and maintain. The methods that implement the substeps may be delegated to other objects or may belong to the same class as the controlling method, in which case they would be invoked by sending a message to self. It will also be easier to override individual substeps in subclasses which require a slightly different implementation.

492 Visual Smalltalk Enterprise Language Reference Coding Guidelines

Breaking a large method into a sequence of smaller methods may result in having to pass around lots of arguments to maintain a large amount of state information. If these arguments are temporary variables, consider whether the code is properly factored in the first place. Perhaps you need to create another class. The instances of the new class would encapsulate the state information and the methods would implement the steps of the computation.

Implementing ‘Equals’ Using “=” vs. “==” One of the more important Smalltalk language features that causes confusion and/or incorrect usage is the implementation of “equals.” There are two methods: “=” (equality) and “==” (identity). Use “=” (read “is equal” or “is equivalent”) to check for equivalency between two objects. Use “==” (read “is identical”) to check for object identity; that is, if two objects are the very same instance (stored in the same memory location (have the same object pointer). Consider the following example where two expressions generate equivalent strings, even though they live in two completely separate objects. 'smalltalk' = ('small' , 'talk') "returns true" 'smalltalk' == ('small' , 'talk') "returns false" In the next example, only one string object is created. | a b | a := 'smalltalk'."create the first string" b := a "create a second pointer to the same string" In all Smalltalk versions: a = b "returns true" a == b "returns true" A third example may evaluate differently on different compilers. | a b | a := 'smalltalk'. b := 'smalltalk'

Visual Smalltalk Enterprise Language Reference 493 Appendix B

In all Smalltalk versions: a = b "returns true" If the compiler optimizes the code by noticing that the same literal string was used twice and creating only one instance of the string, the following expression evaluates to true; otherwise, it is false. a == b "result is unpredictable" Object Implementation of “=” The implementation of “=” in the Object class is the same as that for “==.” That is, two objects are considered equal if and only if they have the same object pointer. You might want to override the “=” method if you want to be able to compare two of your own objects for logical equivalence. A number of system classes, besides String, override this message. For example, following is the Visual Smalltalk implementation for Date: = aDate "Answer if the receiver is the same as ."

^(self class == aDate class) and: [self day = aDate day] If you implement an “=” method, you will almost certainly need to implement a hash method. For two objects to be equal, their hashes must be equal. A hash function is a simple function on an object which returns a SmallInteger. The default hash function inherited from Object is based on the object's identity, not on its value. You will find most of the implementers of “=” also implement hash. The ones that do not must inherit an appropriate hash method. Date is a good example of a system class that implements a hash method. hash "Answer the integer hash value for the receiver." ^day hash The exact implementation is not important. What is important is that any two dates that have the same year and day (the test for “=”) will always have the same hash value.

494 Visual Smalltalk Enterprise Language Reference Coding Guidelines

Never Override “==” The implementation of “==” in Object checks to see if two object pointers point to the same object. To ensure that your image will work properly, never change or override this method. Never Override basicHash basicHash is a hash code explicitly based on the object identity and, like “==,” has a very few special implementations. You should never override or change this method.

Testing for nil When should you use isNil instead of == nil? Typically, == nil is used to identify uninitialized variables or variables that have no interesting value. isNil, on the other hand, is used to determine if the object itself is logically nil. Consider a set of classes representing a tree structure. You might want to represent a mathematically nil node with a NilNode class. Instances of this class would always respond to isNil with true and other Node instances would answer false. You would use the isNil method to test for a node actually being a NilNode and == nil to see if the node is uninitialized.

Visual Smalltalk Enterprise Language Reference 495

Appendix C Error Messages Introduction Visual Smalltalk is a robust and reliable development environment that protects you from conditions that would result in unrecoverable errors in other integrated development environments. For example, potential stack overflows are intercepted before they cause the application to crash and a Smalltalk error is generated. However, a development environment as flexible as Visual Smalltalk allows a variety of actions that can, under certain circumstances, cause problems. To protect yourself from the worst consequences, follow these guidelines: • Keep the installation diskettes in a safe place. • Keep a backup of the installation diskettes. • Keep as current a backup of your image as possible. • Keep a backup of your change log and sources.sml as current as the backup of your image. (Back them up as a trio.) Understand the purpose of the change log and how to use it. • Save your image before you try an operation you suspect may cause problems. • Remain aware of the size of your image. Before you save, ensure that you have adequate disk space to do so. • Calls to operating system routines can corrupt memory if an invalid parameter is used. Exercise care when calling external routines. If Visual Smalltalk cannot recover from an error, it will try to output a diagnostic message. It first will write the message to the file error.log, then bring up a message box with that message.

Visual Smalltalk Enterprise Language Reference 497 Appendix C Virtual Machine Errors The following sections describe errors that may occur in the virtual machine during run-time. Internal Exceptions The following errors indicate that an error internal to Visual Smalltalk occurred such as stack overflow. • doesNotUnderstand: method missing! Cause: An object received the message doesNotUnderstand: and did not understand it. In Visual Smalltalk as it is shipped, this method is implemented in class Object and inherited by all objects in the system. The implementation is: doesNotUnderstand: message "Sent to the receiver by the virtual machine when the sent to the receiver was not implemented by the receiver." ^MessageNotUnderstood message: message Recommended Action: Determine whether the method doesNotUnderstand: is still implemented in class Object. If not, implement it. Determine whether all classes still inherit from Object. If not, either modify the class hierarchy so they do, or implement the message doesNotUnderstand: in the class that does not. • Virtual machine stack overflow. Cause: The Visual Smalltalk virtual machine stack can grow to approximately 32,000 bytes, but the exact number depends on the details of your application. Normally, Visual Smalltalk will send an error message if the stack is in danger of exceeding its limit. You will receive this message when the stack grows beyond its limit. This error is usually caused by an error in error handling code, possibly in the portion of the code that opens a window. Recommended Action: Check for an unbounded recursion in your application. Make sure walkback windows can still open properly in your image. Check for recursion too deep. Restructure your application.

498 Visual Smalltalk Enterprise Language Reference Virtual Machine Errors

• missing primitive Cause: A primitive required by Visual Smalltalk is missing. This is usually a user primitive; otherwise the system is corrupted in some way. Recommended Action: Make sure any user primitives are available to Visual Smalltalk. If necessary, restore a backup image. • a non-continuable protection violation has occurred. Check ERROR.LOG file. Cause: Loading some portion of Visual Smalltalk has caused a memory conflict. The image may have become corrupted or another program may have overwritten Visual Smalltalk’s memory. Recommended Action: Exit other programs currently running and try to start Visual Smalltalk again. Restore backup Visual Smalltalk image. • unable to register window class. Cause: The operating system is unable to provide some requested service. Recommended Action: If a user function is requesting the service, remove the request. If Visual Smalltalk is requesting the service, the operating system may need to be reinstalled. • message not understood. Cause: An object was sent a message for which it has no corresponding method. Recommended Action: Use the debugger to identify the message and receiver, and revise the program as necessary. Low System Memory Visual Smalltalk will generate a variety of errors that can be caused by low system memory. This could be physical memory or , or swap space on the disk. These errors are:

Visual Smalltalk Enterprise Language Reference 499 Appendix C

• compiler unable to allocate memory. • getMem: Allocation request failed. • not enough memory to load image! • out of address space. • out of memory - unable to continue. • unable to commit requested pages • unable to allocate virtual address space. Cause: Smalltalk tried to allocate memory, but no memory was available to do so. This could have several causes: • Have you mistakenly tried to create an unusually large object? • Is your image accumulating objects after they are no longer useful • Do you have lots of windows open and minimized? • Are you running a large application besides Visual Smalltalk? Recommended Action: These errors are generally fatal. Restart your image. If the error occurred while trying to save the image, your image may be corrupted. In this case, use your backup image and recover changes from the change log. You can decrease the amount of memory that Smalltalk requires by using the Object Filer to only load in large objects when they are needed. . Corrupted Image The following errors are caused by a corrupted image. This can be either the image that is currently running or an image saved to disk.

500 Visual Smalltalk Enterprise Language Reference Compiler Error Messages

• Library version mismatch!(date1) - Date of library saved in image: date2. • The library filename is not bound to the image. • unknown prolog variety • Could not allocate enough memory. • Could not find library: filename. • Could not find the image file: filename • Could not open library: filename. • Could not read library: filename. • Could not read objects of library: filename. • filename library does not have a Smalltalk library format. • Invalid byte code. • malformed process. • Not a Smalltalk library file. • Not a Smalltalk image: filename. • Not a Smalltalk library: filename. • object library version mismatch. • past end of stream Cause: Some object has an invalid pointer or value. This can happen because of a user primitive error or a disk I/O error. Recommended Action: If the corrupted image is a file, use a backup version of the image and carefully examine your CHANGE.LOG file for possible clues as to what corrupted this image. If an image loads but repeatedly becomes corrupted, use an older backup, or file your changes into a release image. If the problem persists, contact Cincom Technical Spport. Compiler Error Messages This following are the compile-time error messages and their likely causes. is not a class already exists, and is not a class. It is probably defined as a global variable. already declared as An attempt was made to define an object that has already been declared as the indicated type: either a special symbol, an instance variable, a temporary variable, or an argument.

Visual Smalltalk Enterprise Language Reference 501 Appendix C

ambiguous variable, defined in multiple pools The referenced variable is defined in more than one pool dictionary, so its value cannot be determined. API primitive is not in an external API class A method uses an API primitive in a class that does not support API calls. APIs can be used only in subclasses of DynamicLinkLibrary or SOMProxyClass. argument missing A keyword message is missing a parameter. There are not enough arguments to match the selector or the block declaration. In a block, there may be a colon without an argument name. bad cascade protocol A semicolon was used to end a statement instead of a period. Cascades should follow message-sends and should be followed directly by a message-send. cannot assign to argument Method arguments cannot be stored into. cannot assign to class Classes are special global variables that cannot be stored into directly. cannot assign to a pool variable within The named pool is defined as a constant pool, so its variable names cannot be assigned values. cannot assign to a special symbol An attempt was made to assign a value to nil, true, false, self, or super. class instance variable is defined in a subclass An attempt has been made to redefine a superclass, adding a class instance variable that is already defined in a subclass. class variable is defined in a subclass An attempt has been made to redefine a superclass, adding a class variable that is already defined in a subclass. code follows "^ expression" Code cannot follow a return expression. constant is missing A “#” is not followed by a value. This occurs only if “#” is the last character in a method.

502 Visual Smalltalk Enterprise Language Reference Compiler Error Messages digit too big A digit is too big for the radix being used. duplicate class instance variable A class instance variable is defined twice, perhaps in a superclass. duplicate class variable A class variable is defined twice, perhaps in a superclass. duplicate instance variable An instance variable is defined twice, perhaps in a superclass. duplicate pool name: A pool name has been duplicated in the class definition. expression missing The assignment value on the right side of “:=” is missing. extra period There is an extra period in an expression. This is only a warning, and the expression still compiles. incorrect selector usage A message selector is incorrectly used, possibly in a cascade. instance variable is defined in subclass An attempt was made to redefine a superclass, adding an instance variable that is already defined in a subclass. invalid array element A literal array is being declared with a nonliteral element. invalid calling convention for this class The API calling convention (api, c, pascal, etc.) is incompatible with the method’s class. invalid class instance variable The name shown is not a valid class instance variable name, probably starting with an upper-case letter. invalid class name The name shown is not a valid class name, probably starting with a lower-case letter. invalid class variable The name shown is not a valid class variable name. invalid instance variable: The name shown is not a valid instance variable name, probably starting with an upper-case letter.

Visual Smalltalk Enterprise Language Reference 503 Appendix C

invalid literal value: The name shown is not a valid literal string. invalid number: The numeric expression is not valid. invalid pool: The class definition names an object as a pool, but it isn’t a pool. invalid primitive keyword The API calling convention name (api, c, pascal, etc.) is not known by the compiler. invalid radix A radix must be greater than zero and less than or equal to 36. invalid receiver The beginning of an expression is not a valid receiver. message pattern missing The compiler couldn’t find this message pattern. It may have been left out of a method definition. method exceeds maximum size A method can be up to 5000 bytecodes. This is about 40KB of source code. missing “:” Symbols containing colons are assumed to be selectors, which requires them to end in a colon. missing “>” A primitive or Application Program Interface (API) descriptor must be enclosed by angle brackets (< >). missing “)” The parentheses don’t match. missing “]” The brackets don’t match. missing “|” Temporary declarations must be enclosed by vertical bars. Block arguments must be separated from the body of the block by a vertical bar. missing array terminator An expected closing right parenthesis is missing. missing character A “$” is not followed by a character.

504 Visual Smalltalk Enterprise Language Reference Compiler Error Messages missing dll primitive name The function name is invalid, not in the target DLL. missing expression A pair of parentheses is empty. That is, the parentheses do not enclose an expression. Remove the parentheses or insert a valid expression within the parentheses. missing primary The argument for a binary selector (e.g., “+,” “*,” “<”) is inappropriate or missing. missing primitive keyword The symbol following “<” is not an API keyword. missing primitive name or number The primitive name or number is missing. more than 128 instance variables are defined The number of instance variables for this class, including inherited instance variables, exceeds the limit. must be an integer A float or other non-integer was used in a numeric expression that only accepts integers. must start with lower case Argument and temporary variable names must start with lower-case letter. needs one argument The to:do: message requires a one-argument block for the second parameter. no digits A number with a radix was declared with no digits. no return expression There is no expression following a “^.” non-pointer class cannot have instance variables The class definition specifies at least one instance variable, but the class is byte indexable, which is inconsistent. not in range 0..255 Primitive numbers must be greater than or equal to 0, and less than or equal to 255. pool named does not exist The class definition refers to a global name that is not defined.

Visual Smalltalk Enterprise Language Reference 505 Appendix C

pool named is not a pool dictionary The class definition refers to a global name that is not a valid pool dictionary. Dictionary’s should be used for pool dictionaries. radix not allowed Negative radixes are not allowed. should be selector The selector is missing, or there was a literal or separator where a selector was expected. subclass has pointers The class definition specifies byte indexable, but an object indexable subclass exists, which is inconsistent. subclass is non-pointers The class is object indexable or has at least one instance variable, but a byte indexable subclass exists, which is inconsistent. subclass named now has more than 128 instance variables A superclass of the named class has been redefined, adding instance variables, causing the named class to exceed the limit. superclass has pointers The class definition specifies byte indexable, but the superclass either has instance variables or is object indexable, which is inconsistent. superclass is non-pointers The class definition specifies object indexable, but the superclass is byte indexable, which is inconsistent. system does not allow mutation of class An attempt was made to modify the named system class in a way that is not allowed. too few types The number of arguments in an API method selector is greater than the number declared in the API call descriptor. The descriptor types must match the method selector arguments, plus one for the API return value. too many )s Mismatched parentheses. too many ]s Mismatched brackets.

506 Visual Smalltalk Enterprise Language Reference Compiler Error Messages too many arguments A block or method has too many arguments declared. Blocks can have zero, one, or two arguments. Methods can have up to 64 arguments. too many block The method has more than 2048 blocks. too many temporaries The method has more than 2048 temporary or block variables. too many types The number of arguments in an API method selector is less than the number declared in the API call descriptor. The descriptor types must match the method selector arguments, plus one for the API return value. undeclared An expression contains a reference to a variable that has not been declared within the scope of the expression. undefined argument type A symbol in the API descriptor is undefined. For a list of available types, see DynamicLinkLibrary class>>initialize. undefined result type The result type in the API descriptor is undefined. For a list of available types see DynamicLinkLibrary class>>initialize. unfinished comment Comment double quote delimiters (") are mismatched. unfinished string String single quote delimiters (') are mismatched. Unknown ApiFormat compilation option value: The ApiFormat compilation option was given the invalid value shown. unrecognized primitive name This message occurs if a name, rather than an index, occurs after the “primitive:” keyword.

Visual Smalltalk Enterprise Language Reference 507 Appendix C Compiler Warning Messages The following warning messages pertain to the Visual Smalltalk 3.1 syntax and semantics. Obsolete use of block argument The scope of block arguments is now restricted to the block. nil, true, or false in array is not a symbol The special literals nil, true, and false must now be prefixed with # in arrays. array without # used in array Array literals in an array literal must now be prefixed with #. name without # used in array All literals must now be prefixed with # in arrays. has same name as Variables or arguments in nested scope have the same names.

508 Visual Smalltalk Enterprise Language Reference Appendix D Implementation Limits This appendix describes aspects of the system’s inner workings that impose restrictions on certain implementations. Open-coded Blocks All control constructs in Smalltalk are defined as operations involving blocks, but, in the interest of performance, certain of these messages are optimized by the compiler—that is, the blocks are in-lined in the method. Ordinarily, literal blocks (code inside square brackets) create BlockClosure instances when compiled. These BlockClosures reference separate methods, and create separate contexts when invoked. By contrast, in-line optimized or “open-coded” blocks have their code generated inside the defining method and do not have associated BlockClosures; their arguments and temporaries are merged into the enclosing method’s context as “compiler-generated temporaries.” The following constructs are subject to block open-code optimization by the compiler: BlockClosure>>whileTrue BlockClosure>>whileTrue: BlockClosure>>whileFalse BlockClosure>>whileFalse:

Boolean>>and: Boolean>>or: Boolean>>ifTrue: Boolean>>ifFalse: Boolean>>ifTrue:ifFalse: Boolean>>ifFalse:ifTrue:

Number>>to:do: Number>>to:do:by: For the most part, blocks that are open-coded by the compiler have the same semantics as ordinary blocks. But there are some distinctions that should be noted with respect to context materialization and visibility.

Visual Smalltalk Enterprise Language Reference 509 Appendix D

Browser Visibility Because the compiler rewrites the methods for open-coded blocks, the methods that use these messages do not register as senders of the message. For example, the expression: 1 to: 5 do: [:i | ] is compiled as if it were: | t1 | t1 := 1. [t1 <= 5] whileTrue: [ti := t1 + 1] Hence, it isn’t thought to be a sender of to:do: at all, (or even whileTrue: because that is also open-coded), but it is considered to be a sender of +. All this means in practice is that you can’t use the browser to find the senders of the 12 messages listed in “Open-coded Blocks.” Performance Blocks that contain ^ returns or reference to outer scope variable are less efficient than blocks that do not. For example: | t | [:x | t := x frobnicate] value: 1. t := t * 2. ^t The reference to t inside the block makes it less efficient. Instead, you might write the following, which leaves the block clean: | t | t := [:x | x frobnicate] value: 1. t := t * 2. ^t Non-overridable Methods Some methods are treated specially by the execution machinery and cannot be overridden. These optimizations are done for performance reasons. For example, the == method in Object is hard-wired because it cannot be permitted to fail for obvious reasons. Any == method you create will not take effect.

510 Visual Smalltalk Enterprise Language Reference Non-overridable Methods

Special Treatment Only at Compile Time The following messages are treated specially by the compiler only at compile time: anObject and: aBlock0 anObject or: aBlock0 anObject ifTrue: aBlock0 anObject ifFalse: aBlock0 anObject ifTrue: aBlock0 ifFalse: anotherBlock0 anObject ifFalse: aBlock0 ifTrue: anotherBlock0 aBlock0 whileTrue: anotherBlock0 aBlock0 whileTrue aBlock0 whileFalse: anotherBlock0 aBlock0 whileFalse aBlock0 repeat anObject to: anotherObject do: aBlock1 anObject to: anotherObject by: aNumber do: aBlock1 If the receiver and/or argument(s) meet certain syntactic requirements, these messages are compiled open; otherwise, they are compiled as ordinary message sends. The following example is compiled as an ordinary message (and will cause a messageNotUnderstood error when executed). 1 and: 2 The requirements for open compilation are indicated in the message descriptions above. “aBlock0” or “anotherBlock0” means the receiver or argument must be a literal 0-argument block. “aBlock1” means the argument must be a literal 1-argument block. “aNumber” means the argument must be a literal number. The effect of open compilation is that adding, removing or changing definitions of these messages in certain classes will have no effect on the execution of expressions that meet the open compilation requirements, specifically: • Any class and: or: ifTrue: ifFalse: ifTrue:ifFalse: ifFalse:ifTrue:

Visual Smalltalk Enterprise Language Reference 511 Appendix D

• BlockClosure whileTrue: whileTrue whileFalse: whileFalse • Any class to:do: to:by:do: Note that if the receiver and arguments do not meet the open compilation requirements, the expression is compiled as an ordinary message send. For example, the user can define a method in Integer for and:, and the method will be invoked as expected for: 1 and: 2. Note that the requirements are syntactic, not semantic. For example, something and: [some other thing] compiles open, but something and: someOtherThing compiles as an ordinary message send, which is executed even if the value of someOtherThing turns out to be a BlockClosure at execution time. This is why correct definitions for the above- mentioned selectors must exist in classes Tr u e and False (for the first list above), BlockClosure (for the second list), and Number (for the third). Special Treatment at Compile Time and Translation Time Many messages are compiled using “special selector” opcodes. These opcodes have two different functions: They eliminate the need to store copies of the selector in the sender’s literals, and the translator knows how to compile some of them specially. The translator treats the following selectors specially by generating machine code that performs certain explicit class checks before (or instead of) sending a message. As long as these selectors are compiled as “special selectors,” their definitions for the given classes are fixed and cannot be modified by the user.

512 Visual Smalltalk Enterprise Language Reference Non-overridable Methods

(SmallInteger) + (SmallInteger) (SmallInteger) - (SmallInteger) (SmallInteger) * (SmallInteger) (SmallInteger) / (SmallInteger) (SmallInteger) // (SmallInteger) (SmallInteger) \\ (SmallInteger) (SmallInteger) | (SmallInteger) (SmallInteger) bitOr: (SmallInteger) (SmallInteger) bitAnd: (SmallInteger) (SmallInteger) bitXor: (SmallInteger) (SmallInteger) bitShift: (SmallInteger) (SmallInteger) < (SmallInteger) (SmallInteger) > (SmallInteger) (SmallInteger) <= (SmallInteger) (SmallInteger) >= (SmallInteger) (SmallInteger) = (SmallInteger) (SmallInteger) ~= (SmallInteger) (Object) == (Object) Note that if an addition or subtraction overflows, the expression is handled as a normal message send. If the receiver or argument doesn’t meet the listed criterion, the expression is executed as a normal message send. Note that this is a semantic check carried out at runtime, not a syntactic one.

Visual Smalltalk Enterprise Language Reference 513

Index

Symbols coding guidelines 493–495 - (minus sign) 67 IndexedCollection, class 80 " (double quotation marks) Magnitude, class 61 comments 38 testing for character equality 336 literal strings 76 == (identity) message 50 # (number sign) coding guidelines 493–495 array constants 24 IdentityDictionary, class 79 literal arrays 76 > message literal symbols 76 Character, class 63 $ (dollar sign), character literals 22 Magnitude, class 61 & (ampersand) 169 >= message & message 59 Character, class 63 ( ) (parentheses) Magnitude, class 61 EBNF specifications 459 [ ] (square brackets) enclosing blocks 39 array elements 24 EBNF specifications 459 literal arrays 76 style guidelines 470 overriding precedence order 36 \ (backslash) 169 style guidelines 471 \\ message 72 * ^ (caret), return expression 39 pattern matching 91 { } (braces) * (asterisk) message 67 EBNF specifications 459 + (plus sign) | (vertical bar) arithmetic operator 67 EBNF specifications 459 keycap names and xviii | message 60 . (period) ~ (tilde) cascading messages 36 keyboard accelerator commands 156 message sequences 35 menu item hotkey 169 / (slash) message ~= (not equal) message division 67 Character, class 63 fractions 71 Magnitude, class 61 // message 72 ~~ (not identical) message 50 : (colon) ’ (single quotation mark) block arguments 39 enclosing strings 23 keyword messages 33 Nu meric s ; (semicolon), message cascading 35 < message 256-color bitmaps 106 Character, class 63 A Magnitude, class 61 <= message abortUnbind message 216, 223 Character, class 63 aboutToSaveImage event 314 Magnitude, class 61 aboutToUnbind event 216, 223 = (equality) message 49 abs (absolute value) message 67 Character, class 63 abstract classes class Dictionary 73 implementBySubclass message 57

Visual Smalltalk Enterprise Language Reference 515 Index accessing addMethod:includeSource: message 218, 222 class instances 49 addPoolVariable:named:in: message 222 files 88–89 addresses GDI (Graphics Device Interface) 96 ExternalAddress, class 367 graphics tools 109 addresses See ExternalAddress class indexed instance variables 27 addSubpane: message NLS settings 335 adding subpanes to windows 122, 164 objects within primitives 387–388 addView: message 164 pool variables 30 allFonts message 115 segmented addressing mode 368–369 ampersand (&) 169 shared values 174 & message 59 streams 84 analyzing links 245–246 ActionSequence, class 56 and: Boolean operator activating block arguments 42 MDI mode 440–441 defined 59 active processes animation 96 defined 269 ANSI character set vs. Unicode 326 transitions to other states 270 API calls active profiling sampling method 345 Callback, class 362–364 activeTextPane instance method 444, 446 described 358–362 add: message ExternalBuffers as parameters to 364 adding classes to Smalltalk libraries 219 memory handles 374–375 adding methods to Smalltalk libraries 219 primitive methods 385 OrderedCollection class 81 SOM 433 SmalltalkLibraryBuilder 221 string encoding and 338 SortedCollection 82 user-defined primitives 386 add:named: instance message 221 API functions 337 add:withOccurrences: message 78 API methods 359–362 addClass:IncludeMethods: message 221 appending objects to streams 227 addClass:includeMethods: message 219 application frameworks addExportedItem: message 260 ApplicationCoordinator 170 addGlobalNamed: message 221 described 163 addImport:fromSmalltalkLibrary: message 222 overview 161 adding ViewManager 164 See also add: message ApplicationCoordinator, class API calls 362 as application framework 121, 161 classes to Smalltalk link libraries 218 examples 162 elements to applicationName message bags 78 DDE servers 259 events 172–173 DDEClient, class 256 ExternalBuffer subclasses 365–367 applications help to applications 204–207 See also client applications, DDE; menus to applications 156 Smalltalk libraries; delivering methods to Smalltalk libraries 219 applications; server applications, DDE Object Load Map dialog connections 231 adding help to 204–207 subpanes building to application window views 164–167 ApplicationCoordinator 170–174 to windows 122 ViewManager 164–170 translatable strings to compiled resources displaying status of 333 cursor shapes 157 wm methods to subclasses 379 status panes 131–132 addLast: message 81 multinational 327 addMenu: message 156 opening 91, 164 addMenu:owner: message 156

516 Visual Smalltalk Enterprise Language Reference Index

performance tuning 345 asSet message 76 separating models from views 161 asSmallInteger macro 389 archive instance variable 104 ASSOC.SLL file 90 arcs, drawing 114 associating files 89–91 arcSin message 67 Association, class 79 argument links asSortedCollection message 76 determining which are triggered by event asSymbol message 340 links 245 asterisk (*) triggering 243 pattern matching 91 when created 244 asterisk (*) message 67 arguments asUpperCase message 64 API call 359, 360–361 at: message 27 binary message 32 at:message 49 block vs. Boolean values 60 at:put: message 27, 49 keyword message 33–35 atAddress: method 369 message pattern 37 atEnd message methods with 467 accessing streams 84 naming conventions 469 positioning streams 84 passing in API calls 359 ReadStream end 83 passing to API calls 359 attemptBindTo arithmetic, mixed mode 68 class message 215 ArithmeticError, class 190 attributes Array, class vs. variable accessors 476–477 attributes 73 automatic initialization 489 converting collections to 76 availableFormats message 178 elements of 80 new: message 80 B arrays backColor instance variable 109 See also literal arrays backColor property 159 inappropriate usage of 490 backColor: message syntax 24 setting GraphicsTools colors 120 arrow cursors 157–158 background colors 109, 111 arrow keys BackgroundMixOpaque mixConstant 111 navigating subpanes 129 BackgroundMixTransparent mixConstant 111 asArray message 76 backslash (\) 169 asBag message 76 backupOver: message 342 asByteFileStream message 342 Bag, class asCharacter message 62 See also Dictionary, class ASCII values as class Character instances 62 attributes 73 asCompactString message 338 converting collections to 76 asExternalString message 339, 342 described 78 asLowerCase message 64 basePoint message 115 asNormalizedString message 339, 342 bases, number 22 asNormalizedString: message 343 basicAt: message 49 asOrderedCollection message 76 basicAtput: message 49 asParameter message basicHash message 50, 495 Callbacks 364 basicSize message 49 converting batch files 91 Smalltalk objects to Windows struc- behavior tures 359 removing inherited subclass 57 strings between encoding schemes testing object 50 339 Behavior, class 312 ExternalBuffers 365 between:and: message 61, 99 asPHeader macro 389 binary file streams 342

Visual Smalltalk Enterprise Language Reference 517 Index binary messages semaphores and 272 described 32 transitions to other states 271 parsing 36 blocks style guidelines 467 described 39 bind message 216 evaluating 42–43 bindAction message 219–220 storing 227 bindAction: instance message 222 BNF See EBNF binding Boolean evaluation 42 Smalltalk libraries Boolean expressions 59 automatically 241–242 Boolean, class bindAction 219–220 described 59 bindTo: message 212 True and False subclasses 59 to an image 210 booleanAtOffset: message 366 bindTo booleanAtOffset: method 366 class message 212, 215 booleanAtOffset:put: message 366 bit block transfers. See BitBlt operations booleanAtOffset:put: method 366 BitBlt operations borders bitmaps 112 default push button 130 copying graphics 112 window frames 123 GraphicsTool methods for 109 bottomInset: message 124 Bitmap class>>fromFile: message 373 bottomRightRatio: keyword 124 Bitmap class>>fromModule:id: message 373 bound class message 213, 215 bitmap fonts 115 boundingBox instance variable 110 bitmap message 178 braces { } Bitmap, class EBNF specifications 459 described 104–106 buffering data in file streams 88 instances of 103 building loading 373 applications bitmap: class message 177 ApplicationCoordinator 170–174 bitmap: instance message 178 multinational 327 bitmapHandle instance variable 104 ViewManager 164–170 bitmapInfo instance variable 104 Smalltalk link libraries 216–223 bitmaps buildView:ForModel: message 171 BitBlt messages 112 Button, class 132 clipping 316 byte array described 104 literal 25 drawing 135 ByteArray, class drawn buttons 132 attributes 73 getting from clipboard 315 elements of 80 Tool object 132 byteAtOffset: message 366 blank lines in code 469 byteAtOffset: method 366 block byteAtOffset:put: message 366 limitations 509–510 byteAtOffset:put: method 366 optimized 509 bytesAtOffset:count: message 366 block arguments bytesAtOffset:count: method 366 and: and or: messages 60 bytesAtOffset:put: message 366 colon (:) in 39 bytesAtOffset:put: method 366 condition execution messages 41 framingBlock: message 128 C naming conventions 468 C structures 370 sort blocks 82 CallBack BlockClosure class 509 release message 364 blocked processes CallBack, class 362–364 defined 269 described 362–364

518 Visual Smalltalk Enterprise Language Reference Index callbacks charSize message 115 from APIs 362 charWidth: message 116 from SOM classes 437 check boxes 133 capitalization of variable names 468–469 See also GroupBox, class caret (^), return expression 39 CheckBox, class 133 carriage returns/line feeds CheckBox, class See also ThreeStateButton, displaying menu items 169 class file streams 88 checkItem:forAIIMDIChildMenus: instance testing for 63 method 444 writing to child panes 167 Streams 86 childActivated event 446 cascading messages childClosed event 446 described 35 childDeactivated event 446 indenting 472 class definitions yourself message and 50 class instance variables 28 change message 157 differences between source/target images CHANGE.LOG file 226 sourceObject instance variable and 311 instance variable declarations 27 changed: event object load map dialog 229 list pane selections 168 pre-specifying changes to 231 SharedValue instances 173 resolving changes to 228 user-selections in window panes 167 class instance variables changed: message See also class variables; instance variables subpanes 123 described 28 changed:with: message naming conventions 469 subpanes 123 usage guidelines 480–481 changing use of 26 cursor shapes 157 where defined 26 DDE data items dynamically 261 class message file line ending formats 88 described 49 indexed instance variables 27 isFoo messages vs. 50 LayoutFrame instances 124 class methods pen widths 113 coding guidelines 473–475 shared values 173 DragDropObject 177 sort blocks 82 DragDropSession 179 system methods 475 initialization methods 170 character case, language settings 335 initializing subclasses 48 Character, class MDIChild 444 described 62–64 MDIFrame 445 double-byte character set 337 SmalltalkLibraryBuilder 220 CharacterConstants global variable 309 specifying events objects can trigger 52 characters class names as global variables 29 backing up in file streams 342 class reports 235–236 comparing 63 class variables conversion messages 64 See also class instance variables; instance as elements of String and Symbol 80 variables inserting into strings 338 adding to Smalltalk link libraries 218 reading from ReadStreams 83 described 27 returned from WriteStreams 83 naming conventions 469 syntax 22 usage guidelines 479–480 TextTools drawing 112 use of 26 Windows NT Unicode 326 where defined 26 writing to WriteStream 83 Class, class 312 characterTyped property 159

Visual Smalltalk Enterprise Language Reference 519 Index classes closing adding to Smalltalk libraries 216, 218 files 88 checking for types of 486–488 CMY (Cyan, Magenta, Yellow) color model 117 comments 472–473 Code Generator, PARTS Workbench defining public interfaces to 476 overview 249 explicit references 485–486 code pages extending system 475–476 national language selection 327 graphics 98–103 code points installing MDI 439 described 327 MDI 442 mapping character sets onto 336 missing from loaded objects 229 coding guidelines 473–495 missing from transferred objects 226 collect: message 75 multiprocessing 267–273 Collection, class names added to SystemDictionary 309 described 72–82 naming conventions 469 subclasses overriding size method 49 renaming automatically 232 collections supporting DDE data formats 257 attributes of 73–74 system 307–316 converting 76 test methods 475 DragDropObjects 177 writing source code of, to file 310 enumerating 74–76 ClassReader, class 310–311 list box items 133 cleanup blocks pattern matching 91 ensure: message 186 colon (:) ifCurtailed message 188–189 block arguments 39 process termination running 271 keyword messages 33 resumable exceptions 197 color bitmaps 105 cleanUpWindows message 308 color hierarchy 118–119 clicked event color messages 120 default push buttons 129 color models client applications CMY 117 described 255 defined 116 MDI 439 RGB 116 preventing blocking 258 Color, class 120 starting DDE conversations 256 ColorDialog, class 152 client window pane area colors defined 127, 167 creating 119 clientContext message 239 dialog boxes for selecting custom 152 clientContext: message 239 Smalltalk support 116 clientMessageHandler: message 240 used by graphics tools 110 clipboard colors. See also CMY (Cyan, Magenta, Yellow) closing 315 color model; palette instance variable; RGB copying objects to 228 (Red, Green, Blue) color model OLE 422 ComboBox, class 133 opening 316 commander 96 Clipboard global variable 228, 309, 315 comments ClipboardManager, class accessing methods 479 copying objects 228 described 38 described 315–316 executable 474 close instance method notes to translators 332 MDIFrame, class 444 style guidelines 472–473 MDIViewManager, class 446 Common Object Model 391 close message, clipboard 315 common system dialogs closeApplication event 171 described 151–152 closeView instance method 443 CommonSystemDialog, class 151

520 Visual Smalltalk Enterprise Language Reference Index compact class message 214, 215 control structures comparing described 40–43 See also Magnitude, class ControlError, class 190 characters 63, 335 controlling execution dates and times 66 class Boolean subclasses 59 points 99–100 exiting exception handlers explicitly 199– strings 335 202 compatibility ControlPane, class graphics coordinate system 96 as SubPane subclass 123 Smalltalk libraries 209–210 controls CompatibleDirection: message 113 button 132 compiled resources, text strings as 333–334 button list box 139 compileDefinition: message 372 check box 132 CompiledMethod, class container 146 described 311 header 135 compiler errors installing 130 messages 501–507 list view 137 undeclared variable 30 notebook 148 Compiler options 43 OLE 396 compiling progress bar 144 text definitions of translatable strings 333 property sheet 141 components providing application status only 135 See also Smalltalk link library radio button 132 compound document 391 range 142 conditional execution slider 144, 149 blocks and 42–43 spin button 143, 150 described 41 static pane 135 conditional statements, nesting 482–484 status window 145 configuring tabbed page 140 drag/drop events 181–183 track bar 144, 149 event actions 55–57 tree view 138 window pane events 167–169 up/down 142 confirm: message 153 value set 150 constants wizard 142 described 20–25 conventions, notation xvii–xviii usage guidelines 476 conversations, DDE constructEventsTriggered class message 53, DDEClient class instances for each 256 172 described 255 constructEventsTriggered class method 53, terminating 259, 260 444, 445 converting container application 391 between segmented/flat addressing container control 146 modes 368 containsFormat: message 315 characters 64 containsObject message 228 collections 76 contents instance variable 364 file line ending formats 88 contents message integers to ASCII characters 62 accessing streams 84 number types 68 subpane contents 123 Smalltalk objects to Windows structures WriteStream characters, returning 83 359 contents: message 123 strings between encoding schemes 339 contentsOf coordinates, screen class message 215 described 96 Control Panel, OS/2 326 drawing partial arcs 114 Control Panel, Windows 326

Visual Smalltalk Enterprise Language Reference 521 Index

framingRatio: message 126 files 87 retrieving 98 graphics tools 109 coordinator temporary variable 171 help files 204 copy message 51, 112 id dictionaries 333–334 copying keyboard accelerator commands 156 bitmaps to clipboard 316 layout frames 124 graphics 112 MDIChild windows 443–444 objects 51 MDIFrame window menus 447 to clipboard 228 MDIFrame window top pane 441 self descriptions 57 MDIFrame windows 442 out of Smalltalk memory 368 menus 156 objects out of Smalltalk memory 368 modal dialogs 153 copyToNonSmalltalkMemory: message 368 new processes 268 cos (cosine) message 67 Object Filer message handlers 240–241 COUNTRY.SYS file 326 objects (class Number methods for) 68 cr (carriage return) message pool dictionaries 310 writing to Streams 86 pool variables 310 crashes, system pushbuttons 132 passing arguments to API calls 359 rectangles 101 precautions 497 resource-only DLLs 373 protection violations 390 semaphores 272 createDefaultWindowLink: aPart method 244 SmalltalkLibraryBuilder instances 217 createIdDictionary: class message 333 specified files 227 createLinkFrom:event:to:message: instance ToolPanes 132 method 246 translatable string dictionaries 328–329 createView message 164 user interfaces 121 createViewFor: method 171 views 164–165 creating window panes 122–156 See also building; declaring; defining windows 122–156 application string definition files 331–332 cross-hairs cursor 158 applications CUA Controls 146 ApplicationCoordinator 170–174 currencyFormat message 335 ViewManager 164–170 current message 65, 314 bitmaps 104 CurrentProcess global variable 269, 309 Character instances 64 Cursor display message 157 class instances 48 Cursor global variable 157, 309 Collection classes 76, 77 Cursor hide message 157 Date 65 cursor keys. See arrow keys FileStream 88 Cursor reset message 157 Interval 80 cursor, mouse ObjectChangeMap for renamed class- candidate drag/drop targets 176 es 232 CursorManager, class 157–158 ReadStream 83 customizing Object Filer 236 SelfDefinedStructure 370 SortedCollection 82 D Time 65, 66 data TimeStamp 65 See also data items, DDE; DDE (Dynamic WriteStream 83 Data Exchange) colors 119–120 buffering 88 directories 89 cultural dependent formatting of 335 double-byte symbols 340 data items, DDE event tables 313 changing dynamically 261 exception filters 194 dynamically exporting 261 File Selection dialogs 152 exporting 260

522 Visual Smalltalk Enterprise Language Reference Index

hot links with 256–257 global variables 29 requesting, from servers 257–258 links 244–245 submitting to servers 258 menu items 169 warm links with 257 menus 169–170 data objects, storing. See Object Filer public interfaces to classes 476 data structures SelfDefinedStructures 370 ExternalBuffer, class 364 dependentLinks message 245, 247 Date, class descender message 116 described 65–67 description message NationalLanguage and 335 class Exception 191 system country settings 327 signal: message and 193 date:time message 65 description: instance message 220 dateAndTimeNow message 65 destinationObject message 247 dateFormat message 335 detect: message 75 dates detect:ifNone: message 75 cultural-dependent formatting of 335 developing multinational applications 329–331 returning current 65 deviceContext instance variable 104, 110 dateSeparator message 335 DeviceContext, class 356 DBCS (Double-Byte Character Support) dialog units 154 See alsodouble-byte characters dialog windows, help files and 205–206 DDE (Dynamic Data Exchange) DialogBox, class DDEClient, class 256–259 help files 204 DynamicDataExchange, class 255 modal or modeless dialog behavior 154 overview 255 processing user input 155 DDEClient, class dialogs described 256–259 described 151–153 vs. DynamicDataExchange class 255 OLE 395 ddeExecuteCommand: message 262 opening 153 ddeExportItem: message 261 without resources 154 ddePokeItem:object: message 261 DialogTopPane, class DDEServer, class described 122 described 259–261 help files 204 messages 261–262 Dictionary, class vs. DynamicDataExchange class 255 See also Bag, class dead processes attributes 74 defined 269 as class HashedCollection subclass 78 process state transitions to 271 described 79 deallocating event tables 313 registration database interface and 452 debugger processes 271 vs. class IdentityDictionary 73 decimal points. See Float, class digits decimalPlace message 335 determining if characters are 63 decimalSeparator message 335 returning character values in 64 declaring digitValue message 64 class instance variables 28 direction keys. See arrow keys drag/drop source/target panes 176 directories, creating 89 instance variables 27 Directory, class default push buttons 129–130 creating files 87 defaultAction message 199 described 89 DefaultPalette class variable 106 directory: instance message 220 defaultPushButton message 130 disableItem:forAllMDIChildMenus: instance define:withFields: message 370 method 444 defining disableSystemMenuItemClose instance method events 52–53 443 exception handlers 191 disabling drag/drop 181

Visual Smalltalk Enterprise Language Reference 523 Index

Disk global variable DoubleByteString, class completing pathnames 87 asSymbol message to 340 current directory pathnames 89 attributes 73 defined 309 converting Strings to 337 Display global variable 103, 108 defined 337 displayHelp: message 207 vs. classes Symbol/DoubleByteSymbol 73 displaying DoubleByteSymbol, class 340 application status 131–132, 157 attributes 73 bitmaps 132 vs. classes String/DoubleByeSymbol 73 combo boxes 133 down state, Pen 113 cursors 157 down: message 100 drop-down lists 133 drag/drop events triggered by subpanes 122 Display pen and 108 File Selection Dialogs 152 objects 176 help panels interactively 207 OLE 423 MDI mode tool/status bars 441 drag/drop operations message boxes 153 DragDropObject, class 177–179 Object Filer messages 240–241 DragDropSession, class 179–181 static text 135 overview 175 division programming interface 176 Fraction, class 71 source/target panes 181–184 messages performing 71 user interface 175 DLLs (Dynamic Link Libraries drag/drop sessions 176 API calls and 358–362 Drag/DropObject, class 177–179 DLLs (Dynamic Link Libraries) DragDropObject, class resource-only 373 implementation of drag/drop objects 176 DLLs (Dynamic link libraries) messages 177–179 API calls 358–362 paralleling DragDropSession hierarchy containing translatable strings 333 177 do: message DragDropSession, class block evaluation 84 described 179–181 Dictionary, class 79 implementation of drag/drop sessions 176 enumerating collections 75 messages 179–181 doesNotUnderstand: message dragSessionClass: message 183 class Message instances passing 312 dragSource message 181, 183 not understood 498 dragSource: message 181 reporting exceptions 57 dragSourceCut: event 182 SelfDefinedStructure using 372 dragSourceNeedsObject event 182 dollar sign ($), character literals 22 dragTarget message 181 DosDLL, class 357 dragTarget: message 181, 184 dotProduct: message 101 dragTargetDrawEmphasis: event 183 double quotation marks (") dragTargetDrop: event 183 comments 38 dragTargetEmphasisDefault message 184 literal strings 76 dragTargetEmphasisItem message 184 Double-byte character support dragTargetEmphasisPane message 184 described 337 dragTargetEmphasisSeparator message 184 multi-national support 337 dragTargetEnter: event 182 double-byte characters dragTargetEraseEmphasis: event 183 See also DBCS (Double-Byte Character dragTargetForFormats:operations: message Set) characters 181, 184 equality testing 336 dragTargetLeave event 182 FileStreams 341–342 dragTargetNeedsOperations: event 182 languages requiring 327 dragTargetOver: event 182 drawing

524 Visual Smalltalk Enterprise Language Reference Index

arcs 114 environment, Smalltalk characters 112 ServiceRegistry, class 315 ellipses 114 switching between MDI and non-MDI graphics (GraphicsTool classes) 109–116 modes 449 lines 113 equality (=) message 49 vector graphics 113–114 Character, class 63 DrawnButton, class 132 class Dictionary 73 drawPicture: message 115 coding guidelines 493–495 drawRetainPicture: message 115 IndexedCollection, class 80 DropDownList, class 133 Magnitude, class 61 dump:on: message 242 equality of objects 49–50 dumps error handling preprocessing 236–237 OLE 405 duplicate objects, Bags and 78 error messages Dynamic Data Exchange. See DDE (Dynamic compiler 501 Data Exchange) virtual machine 498 DynamicDataExchange, class Error, class 190 described 255 as Exception subclass 190 overview 355 nonresumable exceptions 194 DynamicLinkLibrary, class ERROR.LOG file 390, 497 DLL module handles 358 error: message overview 355 user interface process errors 271 ShellDLL subclass 89 errorAbsentObject message 75 errors E loading objects 228 e, exponential notation 22 protection violations 390 EBNF (Extended Backus Naur Formalism) reporting exceptions 57 rules 459–463 storage/load processing 238 editing undefined methods 312 links 245 user interface process 271 text definition files 332 virtual machine 497–501 elements, collection evaluating duplicate 76 expressions enumerating 74–76 from DDE applications 264 FixedSizeCollection subclasses 80 messages 51 ordered by indices 79 evaluation order of precedence writing to Streams 86 arithmetic operators 67 ellipses, drawing 114 even message 68 enableItem:forAllMDIChildMenus: instance event handlers method 444 drag/drop operations 181–183 enabling DragDropSessions 179 code generation 250 querying 246 enabling drag/drop 181 registering ensure: message described 55–57 described 186 window pane 167 nested protection blocks 189 subpane properties 122 resignalAs: message causing execution of event links 243 202 event tables 313 ensuring execution event tables, installation of links into 246 always 186–187 EventManager, class overview 185–186 event managing mechanisms 312 under exceptional circumstances 188–189 events EntryField, class 133 See also registering, events enumerating collections 74–76 configuring

Visual Smalltalk Enterprise Language Reference 525 Index

actions 55–57 executing DDE commands drag/drop 181–183 ddeExecuteCommand: message 262 window pane 167–169 executeCommand: message 258 defining 52–53 execution described 52–57 See also controlling execution; conditional determining links triggered by 245 execution; iterative execution; discrete simulation of 267 terminating execution displaying, triggered by subpanes 122 ensuring DragDropSessions 179 always 186–187 exceptional 190 under exceptional circumstances MDIChild 444 188–189 MDIFrame 445–446 of primitives 385 names of 53 resumable and nonresumable exceptions processing OS/2 messages 382 194–197 SessionModel, class 314 sampling methods 345–346 triggering 54 scheduling process 271 eventsTriggered instance variable 52 execution tree, Performance Profiler report 350 eventsTriggered message 169 existingFileNamed: message 87 eventTable message 313 exit: message 199 eventTableForEdit message 313 exiting EXAMPLES exception handlers explicitly 199–202 Resource DLL 373 Smalltalk/V UPRIM.C 386 exitSession message 314 user primaries 386 exitSession message 314 exception environment 197–199 exp (exponent) message 67 exception handlers explicit class references 485–486 described 191–193 explicit initialization 488 exception sets and filters 193–194 exponential notation 22 exiting explicity 199–202 exporting DDE data items ordered lists of active 197–199 addExportedItem:object: message 260 exception sets/filters 193–194 dynamic exporting 261 Exception, class expressions subclass specification of resumable and See also binary messages; blocks; boolean nonresumable 197 expressions; keyword messages; unary subclasses 190–191 messages exceptions assigning results to variables 35 See also errors order of precedence 36 defined 189 parsing 36 handling 191–193 testing variables in 30 internal 498 extendedHelpPanelId message 207 reporting 57 extendedHelpPanelId: message 204, 207 resumable and nonresumable 194–197 extent instance variable 110 signaling 193 extent message 104 specifying lists of 193–194 extentFromLeftBottom: message 101 translating 202 extentFromLeftTop: message 101 exclusive OR. See xor: Boolean operator ExternalAddress, class 367 .EXE files ExternalBuffer, class containing translatable strings 333 described 364, 364–373 File Association feature 90 mixed string encoding 340 executable comments 474 overview 356 execute message 158 remote 369 execute: message ExternalBuffer>>fillFromAddress: method 374 File Association feature 90 ExternalGlobalAddress, class 367 executeCommand: message 258 ExternalHandle, class 356

526 Visual Smalltalk Enterprise Language Reference Index

ExternalHeapAddress, class 367 first message 81 ExternalLong, class 367 fixed objects 388–389 ExternalSegmentedAddress, class 368–369 FixedSizeCollection, class EXTRAS attributes 73 file association 89 described 80 Object filer 225 fixed-width fonts 115 Performance profiler 345 fixedWidth message 116 Float, class F described 70 faceName message 116 numbers as objects of 21 false constant 25 floating point numbers. See Float, class False, class floor message 67 Boolean subclass 59 flushing stream buffers 88 described 59 focus, input File Association, class 89–91 default push buttons 129 File class>>execute: message 91 moving 128–129 File Dialog, class 152 font property 159 file dialogs, opening 227 Font, class 115–116 File System Interface classes 87–91 FontDialog, class 152 File, class 87 fonts FileError, class 190 dialog boxes for selecting 152 fileInActivate message 238 get installed fonts 115 fileInActivate: message 230, 233, 239 for:title:file: message 207 fileInFrom message 310 for:title:file:aboutDlgClass: message 207 fileName class method 359 for:title:file:dialogs: message 205, 206, 207 fileName: message 221 foreColor property 159 fileNamed: message 87 foreColor: message 120 fileOut message 310 fork message 268, 270 fileOut: message 311 fork: message 268 fileOutAll: message 311 forkAt: message fileOutMethod: message 311 ready processes 270 fileOutMethod:on: message 311 setting process priorities 269 fileOutOn: message 311 form feed characters. See carriage returns/line fileOutSurrogate: message 239 feeds dump preprocessing 237 format: instance message 178 files format:data: instance message 178 See also Smalltalk link library; Stream formatted entry field 133 classes Fraction, class accessing 88–89 described 71 associating 89–91 numbers as objects of 21 closing 88 fractions. See Float, class creating 87, 227 frame instance method 443, 446 opening 88–89 frame: instance method 443, 447 writing class source code to 310 frameRectangle instance method 443 FileStream, class frameworks, application. See application binary file streams 342 framework NLS support 341–342 framing window panes 123–128 FileSystemEntity, class 87 framingBlock: message 127–128 FileSystemError, class 190 framingRatio message 126–127 fill message 112 free message 48, 368 fill:fromModule:idDictionary: message 334 from:to: message 80 fillFromAddress: message 369 from:to:by: message 80 finalization 58 fromModule:id: message 155, 334 findExecutable: message 90 fromSmallInteger macro 389

Visual Smalltalk Enterprise Language Reference 527 Index functions 388–389 GraphPane, class as SubPane subclass 123 G subpanes as instances of 166 garbage collection grayscale displays 118–119 messages performing 48 > message releasing objects for 313 Character, class 63 GDI (Graphics Device Interface) Magnitude, class 61 accessing 96 >= message setting graphics display units 97–98 Character, class 63 GDIDLL, class 96, 357 Magnitude, class 61 GDILibrary global variable 358 group panes GDILibrary object 357 tabbing across 128 getBitmap message 315 GroupBox, class 135 getBitmapWidth:height: message 316 GroupPane, class getContents event 204 as SubPane subclass 123 getMetaFile message 316 GUI (graphical user interface) getObject message 228 See also user interface process getString instance message 316 creating 121 global variables drag/drop operations 175 adding to Smalltalk link library 217 Help Manager 203 described 28–29 GUI controls names added to SystemDictionary 309 OLE 391 naming conventions 469 GUID 419 in SystemDictionary 309 usage guidelines 481–482 H use of 26 .H files where defined 26 Dialog Box editor 155 GlobalDragDropObject 177 resource 333 GlobalDragDropSession 179 handleAtOffset: message 366 globalRegistry message 315 handleAtOffset:put: message 366 go: message 113 handlers instance variable 314 grammar cross-reference 462 hasActionForEvent: messge 246 graph panes, changes to 168 hasBitmap instance message 178 graphics classes 98–103 hasFormat: instance message 178 graphics demo 96 hash message 50 Graphics Device Interface. See GDI (Graphics hash values Device Interface) See also equality GraphicsConstants pool dictionary 111 described 50 graphicsMedium instance variable sorting collections according to 78 associated with graphics tool 110 HashedCollection, class 78 graphics tools and 109 hasMetafile message 178 GraphicsMedium, class hasNamedInstanceVars macro 389 described 104 hasNullTerm macro 389 subclasses 103–116 hasObject instance message 178 support by class Window 109 hasString instance message 178 graphicsTool instance variable height instance variable 110 storing pens 105 height message tools associated with medium 104 class Font 116 GraphicsTool, class class Rectangle 102 described 109–112 help, menu item preview 131 setting color of 120 HelpIndex topic 204 subclasses 95, 109–116 HelpManager, class 203–207 HelpManager>>map message 207 HelpManager>>map: message 207

528 Visual Smalltalk Enterprise Language Reference Index

HELPTABLE definition 373 implementation limits 509 hexadecimal numbers implementedBySubclass message 57 notation 22 impliedOperation message 180 hiding includes: message 72, 79 cursors 157 includeSource: message 218, 221 implementation details 491–493 inclusive OR. See | message MDI mode tool/status bars 441 indexable instance variables hierarchy at: and at:put: messages 49 Exception classes 190–191 new vs. new: messages 48 magnitude classes 60 indexed instance variables higherOf: message 100 described 27 hInstance message 372 IndexedCollection, class horizontalExtent property 159 attributes 73 hot links described 79 establishing with server items 256–257 IndexedColor, class 119 exporting items to 260 indices terminating 258 at: and at:put: messages 49 hotLinkItem: itemName class: message 256 inheritance hour-glass cursor 158 class instance variable names 28 hours:minutes:seconds: message 65 class variable names and values 27 .hpj files 205 of instance variables 27 hwndOwner message 372 initialize message 173 initializing class instances 48 I initialize: message I-beam cursor creating class instances 48 displaying 158 new: message sending 48 Icon, class 373–374 initializeEventsTriggered message 53 icons initializing drawing 135 applications 164 MDI mode 441 class instance variables 28 identity 49–50 class instances 48 identity (==) message 50 class variables 27 coding guidelines 493–495 coding guidelines 488–490 IdentityDictionary, class 79 eventsTriggered instance variable 52 IdentityDictionary, class objects after startup 375, 376 attributes 74 subclasses 48 described 79 initWindowSize message 154 event table implementation 314 inject:into: message 75 vs. class Dictionary 73 input focus. See focus, input ifCurtailed: message inserting described 188–189 characters into strings 338 nested protection blocks 189 inset: message 124 resignalAs: message causing execution of Inspect It (Smalltalk menu) item 202 pool contents 310 ifFalse: message 41 installation ifTrue: message 41 optional controls 130 image controls 135 installing image, Smalltalk File Association feature 90 binding Smalltalk libraries 210 MDI classes 439 class definition differences between 228 Object Filer 226 corrupted 500–501 part as Smalltalk 250 saving Performance Profiler 346 with bound SLL 211 instance methods MDIChild 443

Visual Smalltalk Enterprise Language Reference 529 Index

MDIFrame, class 444 isLeftAndAbove: message 99 SmalltalkLibraryBuilder 220–222 isLeftAndBelow: message 99 instance variables isLeftEqual: message 99 See also class variables; class instance isLetter message 63, 337 variables isLowerCase message 63 described 27 isMDIChild instance method 443 naming conventions 468, 469 isMDIFrame instance method 444 numerators and denominators 71 isNil message object pointers and 387 vs. == nil 495 returning number of 49 isPointers macro 389 specifying mappings 231–235 isResultLink message 245, 247 usage guidelines 479 isResumable message 197 use of 26 isRight: message 99 where defined 26 isRightAndAbove: message 99 instances, class isRightAndBelow: message 99 accessing 49 isRightEqual: message 99 creating 48 isSeparator message 63 Integer, class isSmallInteger macro 389 described 71–72 isUpperCase message 63, 337 hot links with DDE data items 256 isWellDefined message 247 warm links with DDE data items 257 item: message 257 integers item:integer: message 258 constants 21 itemIds message 155 interestingImports message 222 iteration methods 68 interface. See GUI (graphical user interface) iterative execution 41 interrupt requests 308 interrupts K adding to Virtual Machine queue 381–382 KernelDLL globalLock: method 374 void addInterruptC function 389 KernelDLL, class 357 InterruptSelectors global variable 381 KernelDLL>>globalFree: method 374 interval testing. See Magnitude, class KernelLibrary global variable 358 Interval, class KernelLibrary object 357 attributes 73 keyboard accelerator commands described 80 described 156 invalidMessage message 57 menu item 169 .IPF files 204 keyboard mnemonics. See keyboard isAbove: message 99 accelerator commands isArgumentLink message 245, 247 keys, dictionary isBelow: message 99 lookup 79 isBelowEqual: message 99 keyToggled event 444, 446 isBound keyword events class message 215 names of 53 isBytes macro 389 registration messages 55 isCompiled message 372 keyword messages isCompiled: message 372 described 33–35 isDigit message 63 indenting 471 isEmpty message 72 parsing 36 reading Streams 84 style guidelines 467 stack/queue vocabulary equivalents 81 isEventLink message 245, 247 L isImage message 116 label: instance method 443 isIndexed macro 389 labels: message 169 isInternalArgumentLink message 247 labelWithoutPrefix: message 166 isLeft: message 99 language module 327

530 Visual Smalltalk Enterprise Language Reference Index language support, national. See NLS (National literals Language Support) byte array 25 LargeInteger, class 71 collection instances expressed as 76 LargeNegativeInteger, class 71 syntax 76 LargePositiveInteger, class 71 liveObjectsIn launching class message 214, 215 Smalltalk/V 211 ln message 67 layout frames 124 loadAllFromPathName:loadMaps: message 233 layoutFrame: message 124 loadFrom:loadMaps: message 233, 234 lazy initialization 488 loadFromPathName:loadMaps: message 233 lead-bytes arrays 343 Loading leadBytes: message 343 part as Smalltalk 250 left: message 100 loading leftAndDown: message 100 Bitmaps 373 leftAndUp: message 100 instance variable values into new class leftBottomPoint rightTop: message 101 definitions 229 leftInset: message 124 objects leftMost: message 100 messages for 227 leftRatio: message 124 missing classes 229 leftTop: message 101 postprocessing activation 238 leftTop:rightBottom: message 101 resolving class definition changes 228 < message pool variables from compiled resources Character, class 63 333 Magnitude, class 61 single string resources 334 <= message translatable application strings dymically Character, class 63 330 Magnitude, class 61 translatable strings into applications 332 letters, testing for 63 LocalDragDropSessions 179 libraryBound event 216 location instance variable 110 limitations logical values 59 blocks 509–510 logicalTool instance variable 110 non-overridable methods 510 LONG, in API calls 367 line drawing 113 longAtOffset: message 366, 370 link firing sequence, modifying 244 longAtOffset: method 366 link message interface 246–248 longAtOffset:put: message 366 link protocol, PARTS Workbench 243–244 longAtOffset:put: method 367 linkArgument:message: message 247 LONGs 367 linkArgument:toEventValue: message 247 lower-case characters linkResultTo:message: message 248 converting characters to 64 links determining if characters are 63 analyzing 245–246 lowerOf: message 100 defining 244–245 lpstrFilter message 372 described 243 lStructSize message 372 sequencing 243, 244 list panes M needsMenu event 168 macros 388–389 list view control 137 magnitude classes 60–72 ListBox, class 133, 181 Magnitude, class 61–62 ListFont global variable 309 MainWindow, class 122 ListPane, class managing memory drag/drop sources/targets 181 OLE 406, 418 as SubPane subclass 123 map dictionaries 205 subpanes as instances of 166 mapping modes, GDI 97 TextTools and 112

Visual Smalltalk Enterprise Language Reference 531 Index matching OLE items 394 objects by patterns 91 setting for subpanes 123 math coprocessors 70 menuTitled: message 156 max: message 62 MenuWindow, class 156 MDI (Multiple Document Interface) message handlers 240–241 activating MDI mode 440–441 message patterns 37 installing classes 439 message polling, Windows 380–381 overview 439 message processing, OS/2 382–384 programming interface 442 message processing, Windows 379–381 MDI Mode (Options menu) item 440 message selectors 37 mdiArrange instance method 445, 447 syntax 35 mdiCascade instance method 445, 447 Message, class MDIChild windows, creating 443–444 described 312 MDIChild, class 442 message: message 153 mdiChildren instance method 445 MessageBox, class 152 MDIClient subpane 442 described 151 mdiCloseAll instance method 445 MessageNotUnderstood, class 190 mdiCloseall instance method 447 messages MDIFrame window cascading 35 applications encapsulated in 441 conditional execution 41 creating 441, 442 converting MDIFrame, class characters 64 as TopPane subclass 442 collections 76 described 444–446 creating mdiGetActive instance method 445 dates 65 MDIMenu, class 447–448 DDEServer object 261–262 mdiMenuBarBuilt event 442, 445, 447 described 31–36 mdiMenuWindow instance method 445 enumerating collections 74–76 mdiMenuWindow: instance method 445 evaluating 51 mdiNewWindow instance method 447 garbage collection 48 MDISsystem, class 449 help panels, displaying 207 mdiTile instance method 445, 447 iterative execution 41 MDITranscript, class 449 link 246–248 MDIViewManager, class 442, 446–447 loading objects 227 memory long chains of 492 compacting object 309 Number, class 69–70 low system 499–500 polling Windows for 380–381 managing using Smalltalk libraries 212 receiving Windows input 380 messages reclaiming 48 registering events 56–57 OLE 406, 418 sequencing 35 memory handles, Windows 374–375 specifying class mappings 233 menu items starting DDE conversations 256 defining 169 storing objects 227 hot keys 169 subpane 123 status pane preview help for 131 supporting translation of 328 Menu, class system, sent to windows/controls 122 MDIMenu class vs. 448 translatable string table entries 332 menus in multiple panes 170 messageSelector message 248 menuBarBuilt event 442, 447 message-sends menus obtaining total number of 348 creating 156 profiler values logged for 352 defining 169–170 MetaClass, class 312 MDIFrame window 447–448 metafile instance message 178 metafile: class message 177 metafile: instance message 178 532 Visual Smalltalk Enterprise Language Reference Index metafiles 106 MixRuleXor mixConstant 111 getting from clipboard 316 mnemonics, keyboard. See keyboard setting clipboard contents to 316 accelerator commands method modal dialogs non-overridable 510 creating 153 method temporaries modeless dialogs 155 initialization of 29 modeling Smalltalk sessions 314 methods 475 models, application accessing 477–479 coordinating with views 163 adding to Smalltalk link libraries 218 separating from views 161, 161–163 API 359–362 modifying bit block transfers (BitBlt) 109 link firing sequence 244 breaking into smaller 492 modifying system methods 475 comments describing 473 modulo operations. See \\ message comments in 38 monochrome bitmaps 105 compiled code of Smalltalk 311 moving creating new objects 66 input focus in subpanes 128–129 declaring drag/drop source/target panes Pens 113 176 multi-media support 456 detecting exceptions 193 multinational application development process example, in code 474 329–331 ExternalBuffer 366 Multiple Document Interface. See MDI implementing SOM methods 437 (Multiple Document Interface) including/excluding in Smalltalk link MultipleSelectListBox, class 133, 181 libraries 219 multiprocessing classes 267–273 indenting 471 naming conventions 466–467, 469 N operating on links 245 name message 223 primitive 384–388 named references to other classes 485 class message 215 referencing class instance variables 28 named instance variables searching superclasses for 31 described 27 Smalltalk Library Builder 217 named: message 370 source code in Smalltalk link libraries 218 nameMap class message 215 specifying, without defining behavior 57 nameMapAt style guidelines 466–467 put subpane 123 class message 215 syntax 37 National Language Support. See NLS (National min: message 62 Language Support) minus sign (-) 67 NationalLanguage global variable 327, 343 mixed string encodings 340 NationalLanguageSupport, class 327 MixedFileStream, class navigating subpanes 128–129 binary file streams and 342 needsContents event 167 described 341 needsMenu event manipulating position of 341 defining menus 169–170 mixed-mode arithmetic 68 list pane creation 168 mixing source/destination pels 111 needsText event 173 MixRuleCopyPen mixConstant 111 nesting MixRuleCopySurface mixConstant 111 blocks 43 MixRuleDefault mixConstant 111 conditional statements 482–484 MixRuleInvertPen mixConstant 111 protection blocks 189 MixRuleInvertSurface mixConstant 111 new message 27, 48, 220 MixRuleNotOr mixConstant 111 creating MixRuleOr mixConstant 111 collection class instances 76

Visual Smalltalk Enterprise Language Reference 533 Index

creating class Notification, class instances 48 as Exception subclass 190 ExternalBuffer subclasses 365 exceptional event represented by 190 Font instances 115 signal and signal: messages 194 open message and 163 NotificationManager, class new: message 220 described 308 creating Notifier class instance 308 class instances 48 Notifier global variable 309 collections of specified sizes 76, 80 notify:withText: message 153 new: method 27 notIndexed macro 389 newDay:month:year: message 65 now message 65 newFileNamed: message 87 number sign (#) next message array constants 24 accessing streams 84 literal arrays 76 reading characters from ReadStreams 83 literal symbols 76 single and double-byte character answers Number, class 341 coordinate system independence 97 next: message 84 creating Interval class instances 80 next:put: message 86 described 67–72 nextPut: message 84 numberOfEventArguments message 248 writing characters to WriteStream 83 numberOfMessageArguments message 248 writing to Streams 86 numbers nextPutAll: message 86 cultural-dependent formatting of 335 nil constant exponential notation 22 class variable initialization 27 syntax 21–22 as default value 25 types 21 testing for 495 types supported 67 NLS (National Language Support) accessing settings 335 O character and string support 336–340 Object Filer cultural-dependent formatting 335 attaching client context to dumps/loads developing multinational applications 327 239 FileStreams 341–342 clipboard operations 228 host system dependencies 326 creating message handlers 240–241 overview 325 customizing 236 separating text strings from application dump preprocessing/load activation 236– code 328–334 239 text comparison, sorting, casing 335 installing 226 nonresumable exceptions loading objects 227 described 194–197 message log 238 return: message 200 object load map dialog 229–231 normal message 158 overview 225 normalized strings 339–340 Smalltalk link libraries and 226 not (negation) Boolean operator 59 storing objects 227 ~= (not equal) message object load map dialog 229–231 Magnitude, class 61 object message 178 Character, class 63 object names, constants and variables as 20 testing objects 49 object pointers 386 ~~ (not identical) message 50 Object, class noTabStop message 128 described 48–58 notation conventions xvii–xviii link messages 246 Notebook control 148 OBJECT.H file 388 notebook control 148 object: class message 177 notEmpty message 72 object: instance message 178

534 Visual Smalltalk Enterprise Language Reference Index

ObjectChangeMap, class 232 OLE objects 391 objectClass class message 179 implementing 407 objectClass instance message 180 OLE support 391 objectClass macro 389 on: message 83 objectCountEstimate: message 221 on:do: message objectLibraryBound: event 314 adding handlers to exception environment objects 197 See also drag/drop objects; receivers defining exception handlers 191 accessing, within primitives 387–388 nonresumable exceptions 194 appending to streams 227 open message 316 copying 51 creating tool panes 132 copying to clipboard 228 MDIFrame windows 442 creating instances 48 new message and 163 describing stored 235 ViewManager subclass instances 164 descriptions of 57 open method equality/identity of 49–50 ApplicationCoordinator 170 finalization 58 dialogs without resources 154 fixed 388–389 initializing application views 163 initializing after startup 375 ViewManager subclasses 164 initializing with SelfInitializingObject 375– open: method 359 376 open-coded block, defined 509 loading OPENFILENAME file definition 371–373 messages for 227 opening missing classes 229 applications 91, 170–172 postprocessing activation 238 clipboard 316 resolving class definition changes 228 dialog boxes 154 OLE 391 file dialogs 227 OS/2 358 File Selection Dialogs 152 SOM 431 files 88–89 storing 227 prompters 153 testing behavior of 50 openModal: message 154 objects message 180 openOn: message objectSize macro 389 initializing application views 163 occurrencesOf: message 72 ViewManager subclass instances 164 OLE openOn: method acquiring interfaces 401 dialogs without resources 154 acquiring objects 400 operating systems aggregation 410 passing strings between Smalltalk and automation 426 338–340 clipboard 422 protocols specific to 209 container application 392, 393 Smalltalk link libraries creating applications 400 compatibility 209–210 dialogs 395 OperatingSystemConstants pool dictionary drag/drop 423 315, 356 enumerators 420 OperatingSystemEventExtra dictionary 379 HRESULT values 419 OperatingSystemEvents array 379 monikers 420 OperatingSystemInformation, class 356 object references 402 operation instance message 180 reference counting 416 operation: message 180 storage 421 operations: message 180 OLE applications 391 or: Boolean operator OLE controls 391 block arguments 42 OLE menu items 394 defined 60

Visual Smalltalk Enterprise Language Reference 535 Index order of precedence overriding precedence order 36 evaluation 36 style guidelines 471 messages 36 parseDotHFile message 155 order of precedence See alsoevaluation order parsing expressions 36 of precedence part OrderedCollection, class code generator 250 attributes 73 partAddedTo: anApplication method 244 converting collections to 76 partDefineLinkForEvent:to:message: message described 81 246 new: message 80 partLinksForEvent: message 245, 246 views instance variable 166 partLinkTriggers message 245, 246 ordering dates and times 66 parts origin coordinate convert to Smalltalk 249 screen location 96 save as Smalltalk library 249 origin message 158 upgrading 253 OS/2 threads 376 parts applications OS/2, IBM determining edit status of 246 message processing 382–384 PARTSEditor, class objects 358 link messages 246 threads 376 partSetLinks:forEvent: message 246 OS2.INI profile definition 326 PARTSLink, class 247 OS2DragDropObjects 177 pass message OS2DragDropSession, class 179 executing enclosing handler blocks 201 outer message exiting exception handlers 199 executing enclosing handlers 201 passive profiling 345 exiting exception handlers 199 pattern matching 91 outline fonts 115 Pattern, class 91 overriding peek message 84 equality and identity messages 50 peekFor: anObject message 85 inherited subclass behavior 57 PeekMessage API 380 shallowCopy message 51 pen message 104 overwriting specified files 227 accessing graphics tools 109 bitmaps and 105 P Pen, class page medium dimensions 110 bitmaps and 105 palette instance variable 104, 106 described 113–114 panes, window overview 95 See also source panes, drag/drop; target perform: message 51 panes, drag/drop perform:with: message 51 adding to application window views 164, perform:withArguments: message 51 166–167 Performance Profiler creating 122–156 installing 346 sizing and positioning 123–128 overview 345–346 subclasses of Window 121 programming interface 352 views as collection of 162 reports 348–351 parameters running 346 constructing placeholders for 328 user interface 347 parent panes 167 period (.) parentheses ( ) cascading messages 36 EBNF specifications 459 message sequences 35 enclosing .PIF files 90 array elements 24 pixels literal arrays 76 bitmaps copying 95 plug and play awareness 457

536 Visual Smalltalk Enterprise Language Reference Index plus sign (+) printing arithmetic operator 67 graphics 107–108 keycap names and xviii Performance Profile reports 352 PMGraphicsLibrary instance 358 printLog: message 352 PMGraphicsLibraryDLL, class 357 printOn: message 57, 86 PMWindowLibrary instance 358 printString message 57 PMWindowLibraryDLL, class 357 priorities, process 268–269 point arithmetic 100–101 process priority 268–269 Point, class Process, class coordinate system independence 97 described 268–271 described 98–101 stacks of incomplete message-sends 267 pointers processes IdentityDictionary key lookups 79 semaphores coordinating 272–273 object 386 simulation of multiple parallel 267 points states 269–271 comparing 99–100 processInput message 155 defined 98 Processor global variable pointSize message 116 creating new processes 268 pointSize:graphicsMedium: message 116 defined 309 pokeItem:itemName object: message 258 ProcessScheduler instances 271 polling Windows messages 380–381 setting process priorities 268 pool dictionaries ProcessScheduler, class 271 containing translatable strings 328, 328– ProcessTermination, class 190 329 PROFILE.LOG file described 30 message-send information 346 names added to SystemDictionary 309 report generated from 348 pool dictionary variables 469 profiling program execution 345 pool variables programming guidelines 465–495 creating 310 progress bar control 144 described 30 Prompter, class 153 usage guidelines 481 properties use of 26 window 158 where defined 26 window subpane 122–123 pop-up menus, drag/drop and 175 PropertyAccessors 92 portable protocols 209 propertyAt position message 84 message 93 position: message 84 put positioning message 93 streams 84 propertyAt: message 158 window panes 123–128 propertyAt:put: message 158 positive message 68 PropertyManager 92 precedence See evaluation order of precedence proportional fonts 115 PresentationSpaceHandle, class 357 protected blocks of code preventing ensure: message 186–187 polling 381 ifCurtailed message 188–189 subpane assignment as tab stop 128 nesting 189 primitive methods 384–388 resumable exceptions and 197 PrintDialog, class 152 protection violations 390 Printer, class protocols described 107–108 accessing streams 84 recommended number of instances 103 Collection, class 77–78 printers, setting up 152 portable 209 SmalltalkLibraryBuilder 220–222 writing Streams 86

Visual Smalltalk Enterprise Language Reference 537 Index pseudovariables 31 registering pushbuttons actions for smalltalkLibraryBound: event classes creating 132 223 default 129–130 event handlers 55–57 window pane 167 Q MDIFrame window events 442 queryButton: message 155 Object Filer message handlers 240 queryItemText: message 155 services 315 queues, OrderedCollections as 81 Smalltalk library mapping dictionaries 242 quo: message 72 registering event handlers quotients, returning 72 links and 246 Registration Database R file associations 90 r, number radix (base) 22 registration database interface radices, number 22 overview 451 radio buttons programming interface 452 See also group boxes; GroupBox, class registration messages, event 56–57 described 132 RegistrationDatabase classesRoot method 452 tab stops 128 RegistrationDatabase localMachine method 452 RadioButton, class 132 RegistrationDatabase new inspect method 452 range controls 142 RegistrationDatabase new keys method 452 rational numbers. See Float, class; Fraction, RegistrationDatabase new value method 452 class RegistrationDatabase oleServers method 452 ratios, scaling rectangles using 124 RegistrationDatabase printHierarchy method RC files. See resource definition files 331 452 reading files 88–89 Registry. See registration database readStream message 88 reject: message 75 ReadStream, class release message 48, 313 creating instances of 83 freeing memory handles 375 detecting end of stream 83 releaseEventTable message 313 ready processes rem: message 72 defined 269 remainders, returning 72 transitions to other states 270 remap:to: message 222 receiveAllWindowMessages message 380 removeExportedItem: message 260 receivers removeFirst message 81 self variable and 31 removeLink: message 244, 247, 248 reciprocal message 67 removeMenu: message 156 recording drawings 114 removing RecordingPen, class exported DDE data items 260 described 114 inherited subclass behavior 57 instant replay 95 links 244 overview 95 menus 156 printing graphics 107, 108 Object Load Map dialog connections 231 Rectangle, class windows invalid in host system 308 See also StaticBox, class replaying drawing recordings 114 as argument to framingRatio: message reports 126–127 dump and load status 238–239 coordinate system independence 97 exception 57 described 101–103 Performance Profile 347 instances converted to LayoutFrame 124 Performance Profiler 348–351 red:green:blue: class message 119 requestItem: itemName class: message 257 red:green:blue: message 119 requestItem:class: message 257 REGEDIT file 451 RESDLL directory 373 register:withName:version: message 315 reset message 84

538 Visual Smalltalk Enterprise Language Reference Index resignalAs: message 199, 202 savedImage event 314 Resource Compiler 333 saveSession message 314 resource definition files 331 saving resource header files 333 event tables 313 resources, Windows 373–374 Smalltalk image result links saveSession message 314 determining which are triggered by event with bound libraries 211 links 245 says: message 194 triggering 243 scaling rectangles 124 resultLink message 248 scanner rules 461–462 resultLink: message 248 scheduling process execution 271 resumable exceptions Screen, class 108 described 194–197 screenLocation message 180 exit: message 199 scripts, building Smalltalk link libraries 217– resume: message 218 exiting exception handlers 199 scroll: message 180 restoring exception environment 200 segmented addressing mode, accessing 369 retainPicture: message 115 select: message 75 retry message selecting exiting exception handlers 199 printers 152 terminating exception handler blocks 200 selection message 123 retryUsing: message selection: message 123 exiting exception handlers 199 selection: method vs. retry message 200 subpanes 123 return expression (^) 39 selectors: message 169 return message self partIsEditing expresion 246 exiting exception handlers 199 self variable on:do: message and 200 described 31 return: message vs. explicit class references 485 exiting exception handlers 199 SelfDefinedStructure, class 370–373 on:do: message and 200 SelfInitializingObject, class 375–376 returning values, caret (^) and 39 Semaphore, class 272 RGB (Red, Green, Blue) color model semaphores described 116 blocked processes 271 RGBColor instance methods 120 described 272–273 RGBColor, class 119 semicolon (;), message cascading 35 rich edit text 133 sendInputEvent: message 379 right: message 100 sequencing messages 35 rightAndDown: message 100 server applications rightAndUp: message 100 described 255 rightBottom: message 101 establishing rightBottomPoint leftBottom: message 101 hot links with items on 256–257 rightInset: message 124 warm links with items on 257 rightMost: message 100 executing commands on 258 rightRatio: message 124 MDI 439 rightTop: message 101 messages to 261–262 rightTopPoint: message 101 not acknowledging application/topic .RTF files 204 names 256 RTF format 133 requesting items from 257–258 starting DDE conversations 259 S submitting items to 258 Samples serviceNamed: ifNone: message 315 user primitive 382 ServiceRegistry, class 315 Save As dialogs 152 services, registering 315

Visual Smalltalk Enterprise Language Reference 539 Index

SessionModel, class 312, 314 sizeLeftTop message 158 Set, class sizeRightTop message 158 attributes 74 sizeVertical message 158 as class HashedCollection subclass 78 sizing converting collections to 76 subpanes 127 described 79 window panes 123–128 setBackgroundMode instance variable 111 skipSeparators message 84 setBitmap: message 316 skipTo: message 85 setButton:value: message 155 slash (/) message setForegroundMode message 111 division 67 setItemText:string: message 155 fractions 71 setLineWidth: message 113 Slider control 149 setMapMode: message 97 slider control 144, 149 setMenu: message 123 SmallInteger, class 71, 80 setMetaFile: message 316 Smalltalk setName: message 167, 204 color support 116 setPeekCount: instance method 308 exception handling mechanisms 185–202 setString: message 316 executing external functions 362–364 setting as instance of class SystemDictionary 29 class instance variable values 28 math coprocessor support 70 foreground/background colors 120 National Language Support 325 graphics display units 97–98 programming guidelines 465 Pen down state 113 simulated parallel processing 267 process priorities 268–269 syntax 19 pushbuttons as defaults 130 syntax summary 459 Smalltalk library descriptions 217 Smalltalk global variable TextContents variable 174 defined 309 window properties 158 as SystemDictionary class instance 29, 309 window subpane contents 123 Smalltalk language 19 window title bar contents 166 Smalltalk Link Libraries shallowCopy message 51 binding 209 shared values 173–174 linking 209 SharedValue, class 173, 312 Smalltalk link libraries ShellDLL, class 89 bindAction/unBindAction 219–220 shellExecute:operation: message 90 binding shellOpen: message 90 automatically 241–242 shellPrint: message 90 bindTo: message 212 shortAtOffset: method 367 binding at startup 211, 212 shortAtOffset:put: message 370 building 216–223 shortAtOffset:put: method 367 compatibility 209–210 shutdown event 314 described 209 signal message 193, 194, 271 dynamic binding 212 signal: message 193, 194 logical names 214 signaling Object Filer and 226 exceptions 193 portability 209 single quotation mark (’) sourceObject instance variable and 311 enclosing strings 23 static binding 211 single-byte characters 336 SmalltalkLibraryBinder, class size message binding SLLs 212 Collection, class 72 smalltalkLibraryBound: event 314 described 49 SmalltalkLibraryBuilder class number of indexed instance variables 27 options 218–220 sizeHorizontal message 158 public protocol 220–222 sizeInBytes message 365 SOM support 431–437

540 Visual Smalltalk Enterprise Language Reference Index sort blocks 82 startup event 314 sortBlock: message 82 StaticBox, class 135 SortedCollection, class StaticGraphic, class 135 attributes 74 StaticPane, class 135 converting collections to 76 StaticText, class 135 described 82 statistical profiling 345 sorting status bars elements according to hash value 78 MDI mode 441 strings, language settings and 335 status window control 145 source code StatusPane (Options menu) item 441 adding to Smalltalk link libraries 218 StatusPane, class 131–132 blank lines in 469 statusPaneHelp: message 131 compiling in all native languages 325 StoredPicture, class creating mechanisms for maintaining 311 described 106 determining total time to execute 348 getMetaFile message 316 including/excluding Smalltalk library 218 instances of 103 separating text strings from application storeOn: message 58 328–334 storeString message 58 writing class, to file 310 Stream classes 82–86 source message 180, 311 stream close message 88 source panes, drag/drop stream flush message 88 declaring 176 stream lineDelimiter messages 88 defined 176 streams described 181–184 accessing 84 determining items selected in 175 appending objects to 227 source: class message 180 positioning 84 source: instance message 180 writing to 86 sourceIndex message 311 strictlyPositive message 68 sourceInFile message 221 string definition files 331–332 sourceObject instance variable 311 string dictionaries, creating translatable 328– sourceObject message 248 329 Sources global variable 310 string message 178 SOURCES.SML file String, class sourceObject instance variable and 311 attributes 73 sourceSeparate message 221 conversion to DoubleByteString 337 sourceString message 311 elements of 80 space characters hot links with DDE data items 256 determining if characters are 63 vs. classes Symbol/DoubleByteSymbol 73 returning width of 116 warm links with DDE data items 257 writing to Streams 86 string: class message 177 space message 86 string: instance message 179 spaceWidth message 116 StringDictionaryReader, class 332, 333 Spin Button control 150 strings spin button control 150 See also literal strings; translatable strings sqrt (square root) message 67 inserting characters into 338 square brackets [ ] NLS support for 337–340 blocks 39 passing between Smalltalk and host 338– EBNF specifications 459 340 style guidelines 470 producing copies of objects 57 stacks returning width of 116 OrderedCollections as 81 separating application code from text overflow of virtual machine 498 328–334 started event 314 syntax 23 startGroup message 129 stringWidth message 116

Visual Smalltalk Enterprise Language Reference 541 Index subclasses target: message 181 See also inheritance targetLocation message 181 adding targetSelection message 181 ExternalBuffer 365–367 targetSelection: message 181 including/excluding in Smalltalk link temporary variables libraries 219 described 29 initializing 48, 489 naming conventions 468, 469 MDIViewManager 446 use of 26 removing inherited behavior 57 where defined 26 subclassing terminal objects 227 Microsoft Windows vs. Smalltalk 380 terminate message 259, 260, 271 OS/2 windows 383–384 terminateHotLinkItem:class: message 258 SubPane, class terminateWarmLinkItem:class: message 259 described 122–123 terminating drag/drop messages 184 DDE conversations 259, 260 subPaneWithFocus instance method 445 hot links 258 super variable 31 warm links 259 superclasses terminating execution implementBySubclass message in abstract of methods 39 57 test methods 475 super variables and 31 Test, class 218 Symbol, class TEST.ICO file 374 attributes 73 TEST.SLL file 382 elements of 80 TestGlobal global variable 218 vs. classes String/DoubleByteString 73 testing symbols characters 63 double-byte characters in 340 file line ending formats 88 syntax 24 numbers, methods for 68 syntax object behavior 50 API call methods 359 variables in expressions 30 described 19 text EBNF 459 displaying static 135 SysFont global variable 310 multiple language support 343–344 system classes 307–316, 475–476 transfering DDE items as 260 system dialogs, common 151–152 translating without affecting code 328–334 system methods, modifying 475 text message 158 SystemDictionary, class text panes described 309–310 direction keys 129 Smalltalk as instance of 29 moving input focus in 129 text strings as compiled resources 333–334 T textContents variable 174 tab characters TextEdit, class 133 determining if characters are 63 TextFont global variable 310 writing to Streams 86 TextPane, class tab message drag/drop sources/targets 181 writing to Streams 86 as SubPane subclass 123 tabbing subpanes 128–129 TextTools and 112 tan (tangent) message 67 TextPaneControl, class 133, 181 target message 180 TextTool, class target panes, drag/drop described 112–113 declaring 176 overview 95 defined 176 threads 376 described 181–184 support for OS/2 376 dropping items into 175 ThreeStateButton, class 133

542 Visual Smalltalk Enterprise Language Reference Index threeStateNotify:withText: message 153 triggering events tilde (~) described 54 keyboard accelerator commands 156 at set intervals 312 menu item hotkey 169 true constant 25 time True, class cultural-dependent formatting of 335 as class Boolean subclass 59 returning current 65 described 59 Time, class 256-color bitmaps 106 described 65–67 NationalLanguage and 335 U system country settings 327 ULONG, in API calls 367 timeFormat message 335 uLongAtOffset: message 367 Timer, class uLongAtOffset: method 367 triggering events at set intervals 312 uLongAtOffset:put: message 367 timeSeparator message 335 uLongAtOffset:put: method 367 Timestamp, class 65–67 ULONGs 367 title: message 170 unary events, names of 53 titles, setting window 166 unary messages to: message 80 described 31–32 to:by: message 80 parsing 36 Toggle, class 132 unBind tool bar, MDI mode 441 class message 212, 215 Tool, class 132 unbind event 223 ToolPane (Options menu) item 441 unBind: message ToolPane, class 132 unbinding SLLs 212 topic: message unBindAction message 219–220 DDE servers 259 unBindAction: message 222 DDEClient, class 256 unbinding Smalltalk link libraries topics, DDE 255, 259 unBind: message 212–214 topInset: message 124 unBindAction 219–220 topLeftRatio: keyword 124 unboundCount class message 214, 215 TopPane, class uncheckItem:forAllMDIChildMenus instance described 122 method 445 help files 204 uncompileDefinition: message 372 topPaneClass message 166 UndefinedObject, class track bar control 144, 149 nil constant 25 Transcript global variable 310 test message 218 Transcript window Unicode character set 326 switching to MDI mode and 440 unitMultiplier message 154 transferring objects between images. See up: message 100 Object Filer update message 123 translatable strings update: message 123 as compiled resources 333–334 update:with: message 123 creating dictionaries of 328–329 updateExportedItem: message 260 loading into applications 332 updating translating exceptions 202 exported items 260 trigger message 248 subpanes 123 triggerEvent: message 54, 173 window panes 173–174 triggerEvent:ifNotHandled: message 54 upgrading parts triggerEvent:with: message 54 resolving class definition conflicts 253 triggerEvent:withArguments: message 54 upper-case characters triggerEvent:withArguments:ifNotHandled: converting characters to 64 message 54 testing for 63 UPRIM.C file 386

Visual Smalltalk Enterprise Language Reference 543 Index

UPRIM.DLL file 382 view temporary variable 171 upTo: anObject message 85 viewing user interface process 271–272 pool contents 310 user interfaces registration database 451 See also GUI (graphical user interface) ViewManager, class creating 121 as application framework 121, 161 Performance Profiler 347 building applications 164–170 user-defined primitive methods 386 coordinating events with messages 162 UserDLL, class 357 help files 205 UserLibrary global variable 358 MDI applications and 443 UserLibrary object 357 MDI classes and 442 USERPRIM.H file 387, 388 MDIFrame window 441 USERPRIM.LIB file 381 vs. ApplicationCoordinator 163 uShortAtOffset: message 367 views instance variable 166 uShortAtOffset: method 367 views, application uShortAtOffset:put: message 367 coordinating with models 163 uShortAtOffset:put: method 367 creating 164–165 separating from models 161, 161–163 V specifying top panes for 122 value message. See also ensure message 42 virtual machine value set control 150 determining interrupt requests at intervals value: message 308 block evaluation and 42 error messages 497–501 changing shared value values 173 logging runime execution profile data 352 converting integers to characters 62 placing interrupts into queue 381–382 creating Character instances 64 stack overflow 498 value:value: message 42 undefined methods 312 values VirtualKeyConstants object 357 assigning to variables 38 void addInterruptC function 389 logical 59 void GCUpdate function 388 primitive data 227 VRESnnW.DLL file 374 ranges supported by class Number subclasses 71 W shared 173–174 wait message 271 variable accessor messages 477–479 Walkback windows variables next message sent to ReadStream 83 assigning values to 38 protection violations 390 described 26–31 warm links naming conventions 468–469 establishing with server items 257 reusing 30, 482 exporting items to 260 shadowing 30 terminating 259 usage guidelines 476–482 warmLinkItem: itemName class: message 257 variable-width fonts 115 Warning, class 190, 194 vector fonts 115 warning: message 153 vector graphics when:do: message 56, 168 class Pen 113 when:evaluate: message 56, 168 vs. bitmapped 95 when:send: message versionOf registering event handlers 55 class message 216 window pane event handlers 168 versions when:send:to: message 56, 167 registering service 315 when:send:to: method 246 vertical bar ( | ) when:send:to:with: message 56, 167 EBNF specifications 459 when:send:to:with: method 246 | message 60 when:send:to:with:with: message 56

544 Visual Smalltalk Enterprise Language Reference Index when:send:to:withArguments: message 56 wm messages, processing 379–381 whileFalse message 41 WM_COMMAND message 155 whileFalse: message 41 Workbench, PARTS whileTrue message 41 See also Code Generator, PARTS whileTrue: message 41 Workbench; framework, property dialog; width instance variable 110 link protocol, PARTS Workbench; width message 102 workbench-time libraries WildPattern, class 91 workspace variables WIN.INI file 326 described 29 WIN.INI initialization file 90 workspaces WinConstants pool 98 workspace variables 29 window handles 380 wrappers window properties 158 for host system dialog boxes 151 Window, class 104 writeFile message 222 controls and panes as subclasses of 121 writeStream message 88 declaring drag/drop source/target panes WriteStream, class 176 creating instances of 83 drag/drop messages 183 returning characters from 83 GraphicsMedium protocol support 109 writing windowClass class message 171 class source code to file 310 WindowDialog, class files 88–89 described 151 dialogs without resources 154 X modal or modeless dialog behavior 154 x message 98 windowFeedback message 221 x: message 98 WindowHandle, class 356 xor: Boolean operator 60 WindowProc 379 windows Y See also panes, window y message 98 allowing for translation of text in 328 y: message 98 creating 122–156 yield instance method 308 creating in OS/2 384 yourself message 50 designing application 164 installing default links for 244 Z as main GUI element 121 ZeroDivide, class 190 Notifier tracking 308 switching to MDI mode and 440 tracking 308 windows instance variable 308 Windows, class 355–356 Windows, Microsoft MDI (Multiple Document Interface) 439– 449 memory handles 374–375 message processing 379–381 resources 373–374 subclassing 380 WinSendMsg 384 WinSubclassWindow 383–384 with: message 77, 376 with: method 376 withAllDependents message 245, 248 withCrs message 169 wizard control 142

Visual Smalltalk Enterprise Language Reference 545

Reader Comment Sheet Name: Job title/function:

Company name: Address: Telephone number: ( ) - Date: / /

How often do you use this product? Dail y Weekly Monthly Less

How long have you been using this product? Months Years

Can you find the information you need? Yes No Please comment. FAX

Is the information easy to understand? Yes No

Please comment. IT! Is the information adequate to perform your task? Yes No Please comment.

General comment:

WE STRIVE FOR QUALITY

To respond, please fax to Larry Fasse at (513) 612-2000.

P46-0201-00