home *** CD-ROM | disk | FTP | other *** search
-
-
- A Guided Tour to CB
-
- Glen Diener
- Center for Computer Research in Music and Acoustics
- Stanford University
- Stanford, CA
- grd@ccrma.stanford.edu
-
-
- Introduction
-
- This is a "guided tour" of Class Builder (CB). CB
- is an application designed to give people
- a flavour of what a Smalltalk-80-like
- programming environment for the NeXT machine
- might look like. It is by no means a complete
- system...my hope is that it will stimulate
- the imagination of people with more time and ability
- than myself to devoting some of their energies to
- the creation of a better program development environment.
-
- The following takes you on a guided tour through the
- capabilities of CB.
-
- 1) The workspace
-
- You are currently looking at a workspace. Think of
- it as simply a long piece of paper on which you can
- type whatever you want. In addition, if you select
- any text using the mouse, then press the Evaluate button
- up in the top left corner ot this window, then
- the selected text will be compiled, loaded, executed,
- then unloaded. As an example, select the following
- snippet of C code, then press evaluate:
-
-
- int i,j = 0 ;
- for(i = 0 ; i < 100 ; i++)
- j += i ;
-
-
- Now, how do you know that the code was executed?
- Well, lets add a statement which prints out the
- result. CB's application object, referenced through
- the global variable "NXApp", understands the
- message printf:, which takes a variable number of
- parameters. printf: works just like the printf()
- function, except that it always writes its output
- into a window called the Transcript. To see the
- Transcript, just go to CB's menu, and click on
- Transcript... Now, lets try the previous code example,
- but with a printf: statement. Select and evaluate the
- following:
-
- int i,j = 0 ;
- for(i = 0 ; i < 100 ; i++)
- j += i ;
- [NXApp printf: "The answer is %d\n", j] ;
-
- The result should have appeared in the Transcript window.
- Anthing which is written to the Transcript is simply
- concatenated to any existing text. To clear the transcript,
- hit the "Clear" button. You cannot edit this text,
- though you can copy it using Command-C.
-
- If there are errors in your program, they will also
- appear in the Transcript window. For example, evaluate
- the following...
-
-
- int i ;
- j = 0 ;
-
- and note the errors and warnings in the transcript.
- It says that on line 2, `j' was undeclared. Note
- that this refers to line 2 of the selected text,
- which may be on any line number in your workspace.
-
- I hate the way Objective C programs always die when
- they don't understand a message. All Objects in
- CB are actually NObjects...NObjects are just like
- objects, except that if they don't understand
- something, they pop up a Panel allowing you to
- either continue or abort the program. To illustrate,
- evaluate the following:
-
- [[[Object new] init] hazanga] ;
-
- --and choose "Continue" from the alert panel.
- NObjects "pose" as objects, so any object you create
- in CB will have this behaviour. Now, if this were
- Smalltalk, an unrecognized message would pop you
- into a debugger, where you could examine the stack,
- define a new message, etc. etc. Anyone interested
- in "grafting" gdb onto CB?
-
-
- The code that you write does not get interpreted: it
- is compiled, linked, and executed just like any other
- C code. CB accomplishes this by creating a new
- "temporary" class and a single class method, called "doit",
- "around" the code you write. This class is compiled,
- then loaded, and the class is sent the message "doit"
- in order to execute the code. Finally, the class is
- unloaded.
-
- The temporary class "knows about" the classes
- "Object" and "HashTable", as well as the class
- "DictManager" (explained in the next section),
- and the external variable "NXApp".
- If you want to send messages to other classes,
- two things need to be done. First, the other
- classes must be loaded (this will be explained
- later). Second, a #import "otherclass.h" will
- have to be created for each of these other classes.
- Workspaces use a special syntax to ensure these
- #import directives end up at the top of
- the "temporary" class definition they create.
- All headers should go between the directives
- #header and #endheader. The following example
- shows how this is done:
-
- #header
- #import <appkit/Window.h>
- #endheader
- id aWindow ;
- NXRect aRect = {{100.0,100.0},{400.0,400.}} ;
- aWindow = [Window alloc] ;
- [aWindow initContent: &aRect
- style:NX_TITLEDSTYLE
- backing:NX_BUFFERED
- buttonMask:NX_CLOSEBUTTONMASK
- defer:NO ] ;
- [aWindow setTitle: "Created by CB!"] ;
- [aWindow display] ;
- [aWindow orderFront: self] ;
-
- You can create as many workspaces as you want; they will
- always have the extension ".wsp". Workspaces are saved
- using the "File/Save" or "File/Save As" menu options.
-
- 2) Dictionaries
-
- What if you wanted to create an object in one hunk of
- ObjC, then reference it in another? CB has a built
- in dictionary for just this purpose. Currently, you
- can save ids, integers, and strings in the dictionary.
- Here is an example of each. Evaluate the following...
-
- #header
- #import <appkit/Window.h>
- #endheader
- [DictManager insertKey: "aWindow" value: [Window new] type: "@"] ;
- [DictManager insertKey: "hello" value: "hello" type: "*"] ;
- [DictManager insertKey: "goodbye" value: "goodbye" type: "*"] ;
- [DictManager insertKey: "a" value: 1 type: "i"] ;
-
-
- Note that the class DictManager is already known to the workspace,
- so you don't need a #import directive for it. Also note that
- you must specify the "type" of the object you are putting into
- the dictionary, using the standard ObjC syntax of "@" for objects,
- "*" for char *, and "i" for integer. To see the results of the
- above evaluation, choose Dictionary... from the menu, and play
- with the browsers you see there. You can change the values
- of the integer and the strings right in the Dictionary Manager,
- by typing in the text view below, then hitting the "New Value"
- button. You can't (yet) change the value of an id this way,
- however. Any of the three types may be deleted. The following
- code shows how to retrieve values from the dictionary...
-
- [[DictManager valueForKey: "aWindow" type: "@"] orderFront: 0] ;
-
-
- --this will put a small window in the left-hand corner of your
- screen. To make it go away, evalute the following:
-
- [[DictManager valueForKey: "aWindow" type: "@"] free] ;
- [DictManager removeKey: "aWindow" type: "@"] ;
-
- (The Dictionary Manager does not (yet) update itself automatically
- to reflect the fact that the Key "aWindow" was removed).
-
-
- 2. The Class Manager
-
- Now we get to the real heart of CB: its ability to help create
- new classes. As an introduction, choose "File Open..."
- from the file menu, and open the file called "Test.m".
- This opens a "Class Manager" window, and displays
- the implementation code for the class Test.
- Click on the Compile button, then on the Load button, and
- class Test is now ready for use! Let's test it out. Before
- you evaluate the following code, you will have to change
- the #import statement to point to the directory you have
- installed CB in...
-
- #header
- #import "/local/grd/CB/Test.h" /* Edit this line !!! */
- #endheader
- [[Test new] howAreYou] ;
-
-
- A few points need to be made here. First, in the file
- "Test.m", look at the first line:
-
- #pragma .h #import <objc/Object.h>
-
-
- This line is there because I refuse to write .h files.
- Instead, an awk script scans the .m file and creates
- the .h file automatically (you can see the script in
- the "compile:" method in ClassManager.m). There does,
- however, need to be a way to put something in the .h
- file which is not read by the .m file. This is the
- purpose of the #pragma .h directive. Everything
- after the #pragma .h , up to the next newline,
- is copied verbatim (minus the #pragma .h, of course!)
- into the .m file. Since the compiler does not
- recognize the #pragma .h, it is essentially a comment
- in the .m file.
-
- Next, note that Test.m imports Application.h. Unlike
- the workspace Evaluation mechanism, where the global
- var NXApp is already known, you must declare it
- (normally by including Application.h). There are
- no "implicit" declarations in Class Manager windows.
-
-
- There is a Panel in CB which is invoked by the
- "Loaded Classes..." menu button. This panel
- displays the names of all the classes which you
- have loaded. It is a scrolling browser in which
- individual classes may be selected and unloaded
- (Unload Sel), or in which all classes may be
- unloaded (Unload All). The order in which classes
- are loaded is important: NeXT's incremental loading
- hooks have an unload module call which doesn't
- specify which module (in CB, module means class)
- to unload! It simply unloads the last one that
- was loaded. So what happens if you load 20 classes,
- then want to go back and modify the first one you
- loaded? You have to unload all 20, modify and reload the
- first, than reload the remaining 19. CB does all this
- for you, however: you can unload any class you want
- at any time. Be aware, however, if you have placed
- an instance of one a class in the dictionary, then you
- change a class that was loaded before you loaded that
- class, the instance in the dictionary will be stale.
-
-
- Finally, here is a more complicated example which uses a nib
- file from the interface builder. A nib file was created,
- using Interface Builder, starting by choosing the
- "File/New Module..." IB menu option. Then a window
- was dragged from Palettes, and a scrolling text view
- placed upon it. In IB's Classes menu, a subclass of
- Object, called IBExample, was created, and the File's
- Owner was set to this class in the File's Owner Inspector.
- A single outlet, called textView, was created, and the
- scrolling text view was "plugged" into it.
-
- Now open the file IBExample.m from CB's "File/Open..."
- menu. Compile and load this class, just as we did
- above for class Test. Then evaluate the following:
-
- #header
- #import <appkit/Application.h>
- #import "/local/grd/CB/IBExample.h"
- #endheader
- id anIBExample ;
- [NXApp loadNibFile:
- "IBExample.nib"
- owner: anIBExample = [[IBExample alloc]init] ] ;
- [anIBExample setText: "An ambition to squint "
- "at my versus in print\n"
- "Makes me hope for these few you'll find room.\n"
- "If you so condescend, then please sirs, at the end,\n"
- "The name of yours truly,\n\t\t\t L. Bloom\n"] ;
-
-
-
- --happy hacking!
-
-
-
-
-
-