Quirk 6 User's Manual

Programmers interested in the underlying workings of Quirk should read the Quirk 6 Programmer's Manual.

Introduction

Quirk is an alternate reality and visual programming environment. With Quirk you can visually model simple physical systems with motion, gravitation, spring force, or interactions of your own design. You can also use Quirk's visual programming features to create complex Smalltalk expressions and message chains without writing any code.

Installation

Quirk 6 requires VisualWorksTM 2.5 or later, and HotDraw. You can download HotDraw and Quirk from from [ FTP LINK GOES HERE ]. Follow this sequence to install Quirk:

  1. Download HotDraw.st, Quirk6.st, and the Warehouse directory.
  2. Move the Warehouse directory to the directory you start VisualWorks from.
  3. Start VisualWorks.
  4. File in HotDraw.st.
  5. File in Quirk6.st.
To open a new Quirk World, type "QWorld open" and do it.

Tutorial

If you haven't already, type "QWorld open" and do it. This creates a new Quirk World.

Creating an Object

Shift-click the Warehouse and select Large Sphere from the resulting menu. This creates a new object in the world with a spherical appearance. Try dragging the sphere around. Try dragging other objects.

Use the Warehouse again to create Motion. Motion is an Interactor which allows objects to experience linear motion. Like any Interactor, Motion applies only to those object which are enrolled in it. Our next step is to enroll the sphere in Motion.

Creating a Button and Enrolling the Sphere

Drag the ButtonMaker (labeled makeButton) on top of Motion and shift-click it to bring up the ButtonMaker menu. This menu shows all the messages which the sphere Object can understand. Choose enroll from the QActor Messages menu. enroll is a message which enrolls an object in an Interactor. Choosing enroll creates a new Button which sends the enroll message.

Drag the sphere on top of Motion, and drag the enroll button on top of the sphere. Shift-click the enroll button to enroll it in Motion.

Turning Motion On

Finally, to allow the sphere to move, turn Motion on by creating an OnOff button in the same manner you created the enroll button, putting the OnOff on Motion, and shift-clicking. Motion should visibly change to [ON]. (Hint: You can turn an Interactor on more easily by middle-clicking on the Interactor and choosing OnOff from the QActor Messages submenu of the Shortcuts submenu).

Now "throw" the sphere by dragging it (slowly) and releasing the mouse button before you stop moving the mouse. The sphere will begin moving at the same velocity as the mouse was moving when you released the button.

Adding gravity

Create a Small Sphere from the the Warehouse. Enroll it in Motion. (Hint: You can quickly enroll all objects in the world in an Interactor by sending the UniversalOnOff message to the Interactor. This works fine for Motion, but be careful! It enrolls all objects, and can have some unexpected effects with other Interactors. Do you really want your Warehouse to have a gravitational attraction to your ButtonMaker ?).

Now create Gravity (another Interactor) from the Warehouse, and enroll both spheres in it. The spheres will begin drifting towards each other under the influence of gravity. If you'd like the gravitational attraction to be stronger, try changing the mass of the spheres by sending them the editAttribute message (using either the ButtonMaker or the Shortcuts menu).

More Fun With Interactors

Create a Bounded Motion interactor from the Warehouse. Make it a universal law by sending the UniversalOnOff message to the Interactor.

Now create a large sphere from the Warehouse. The sphere will automatically be enrolled in Bounded Motion, since we made the interactor into a universal law.

Try throwing the sphere, and you will notice that it remains within a rectangular area. To change the size of this area, you can send the editAttribute message to the Interactor.

Simple Visual Programming

You may want to close your World (which by now is rather cluttered) and start a new one.

Shift-click the ObjectMaker (labelled MakeObject), type a 1 in the field of the resulting window, and click Okay. The ObjectMaker creates a new object representing the Smalltalk integer 1. Create an object representing 4.7 in the same manner, and drag these objects into an empty part of the window.

Move the ButtonMaker onto the 1 object and shift-click it. A menu pops up displaying the value of the object (1), its class, and all of its superclasses. Each item is a submenu containing a list of all messages accepted by the corresponding class. From the arithmetic category of the Integer class, choose +. This creates a Button which sends the + message. Drag the ButtonMaker off the 1, and drag the + Button onto the 4.7 object.

Since + requires a parameter, this button has a small square attached. Drag this square to extend a line and another green box from it. Experiment with dragging the line and the box. Note that all drags are essentially drags of the green box. Try dragging the green box onto the white box. Drag the green box so that the end of the line rests on the 1 object.

Drag the ObjectMaker onto the + Button and shift-click the ObjectMaker. Shift-clicking the ObjectMaker creates a new object with the value of the object below the ObjectMaker. Since the object below the ObjectMaker is a Button, its value is computed by computing the value of its parameter (1) and sending the message (+) with that value to the receiver (the object under the +, or 4.7). The result, 5.7, is the value of the Button, and is created as a new object. (Hint: you can quickly check the value of an object or button without creating a new object by clicking the ButtonMaker on it-- the value of the object will appear in the menu. You can also easily display any value in a separate window using the Displayer).

More Complex Visual Programming

Use the ObjectMaker to create an object with value "List new" (an empty List).

Move the the ButtonMaker to an empty space and shift-click it to bring up a window which allows you to input any method name. Enter "add:" and click Okay.

Drag the add: Button on top of the List new object. Drag the square from add: to the 5.7 object and click add: to add 5.7 to the List. Change the add: parameter to the 4.7 object and add it to the List. Add the 1 object to the List. The list should now be of length 3. Create a new size Button and place it on the List. The value of this button is now 3, because sending size to the list returns 3. Make this size button the parameter to the add: button (by dragging the green square from the add: button and dropping it on the size button), and click add: to add 3 to the List. Finally, create a new string object 'hello' and add it to the List.

Move the ObjectMaker to an empty space and shift-click it to create a new object. Type "[ :each | Transcript cr; show: each printString ]" and click Okay to create a new Block. Note that the Block has a square for its parameter-- this square works the same as the squares on a Button. This block prints its parameter on the Transcript. Experiment with printing various objects on the Transcript by connecting them to the :each parameter of the Block and shift-clicking the Block. Now drag the green box from the :each to the white box to remove the green box. Create a new button to send the do: message, by typing it in the ButtonMaker window. Drag the do: button to the List, and drag the do: parameter square and drop it on the block. Click do:, and the block will be called for each item in the list, printing each in the Transcript.

You can upgrade the size button to an Interactor by selecting Upgrade To Interactor from the menu. Enrolling an object in one of these "upgraded" interactors has the same effect as placing the original button on top of the object and pressing it repeatedly.

Try enrolling one of the objects in the size interactor and then turn the interactor on. A new object will be created which shows the current size. This result will update dynamically as the original object's size changes.

Try adding new items to the list, and watch the size result change.

Using Quirk

Objects

Objects appear as graphical items in the World. Objects can be created using the Warehouse or the ObjectMaker.

Objects in the World can represent any Smalltalk object. Some objects do not represent a specific Smalltalk object, but exist only as World objects. These objects (examples include Sphere and Chalk) generally come from the Warehouse, and are used with the physics simulation features of Quirk.

Every object has a value. For objects which represent Smalltalk objects, their value is the Smalltalk object itself. Other types of objects like Buttons and Blocks compute their values in as needed.

Quirk Objects are referred to internally as QActors, and this name may be used in some parts of Quirk.

Interactors

Interactors represent certain laws that define how objects in the world behave. Each interactor has a set of objects, called the enrollees of the interactor.

When an interactor is turned on, all of the objects that are enrolled in the interactor will follow the behavior defined by the interactor.

For example, all objects that are enrolled in the Motion interactor can be thrown, and they will move according to the user-defined speed and direction.

Each interactor may add certain attributes to the object. These attributes (e.g., acceleration for Motion) can be edited by sending the object the editAttribute message. By altering the values of the attributes, the object's behavior (as dictated by the interactor) can be modified.

Each interactor also has an actionBlock which defines the behavior for all of the enrollees. The block is executed repeatedly for each enrolled object. This too can be edited by sending the Interactor the editActionBlock message.

Interactors can be made universal. When an interactor is made into a universal law, all objects are enrolled in the interactor. In addition, any objects created from the Warehouse or via the ButtonMaker will automatically be enrolled in the universal interactor upon creation. This option is especially convenient for Interactors which represent different physical laws (e.g., Motion, Gravity) that might apply to all objects in the world.

An interactor can also represent a Smalltalk message. To create such an interactor, the user must transform a button into an interactor by selecting the Upgrade To Interactor option from the menu. The effect on enrolled objects is analogous to placing the original button on top of the object and clicking it repeatedly.

This option can be convenient when viewing a value of a given message for an object that might change frequently. By enrolling the object in the interactor, the user can always see the current value that the method returns.

Buttons

Buttons represent Smalltalk messages. Shift-clicking a button sends a message to the object underneath it. You can use the ObjectMaker to convert the result into a Quirk object by putting the ObjectMaker on the button and shift-clicking it.

Buttons which represent multi-parameter messages have one small square for each parameter of the message. This square can be dragged to specify which object should be used as the parameter. Dragging the square creates an elastic line; dropping the end of the line on another object specifies that object as the value of the parameter.

A middle click of the mouse on any object will pop up a context sensitive shortcut menu. Copy, Cut, and Paste have their normal meaning for the object selected. ShortCut has a submenu which includes all of the zero-parameter messages that can be sent to the object. For example, all objects can respond the the growDouble message which doubles the image size for the object. Selecting a message from this ShortCut menu will send the selected message to the object. makeButton will popup a menu of all messages understood by the object. Any selected message will be made into a button in the World. Upgrade to Interactor creates an Interactor from the object.

The ShortCut and makeButton menus are composed as follows: The main menu is a list submenus. The first element is a menu of messages that all objects can handle. If the object represents some Smalltalk object, then the Smalltalk object will be displayed second on the main menu. This submenu contains the catagories and messages of the Smalltalk object's class. The rest of the main menu contains the ancestors of the Smalltalk object with each submenu having the categories and messages that each superclass implements.

The value of a button (used when the the ObjectMaker or the ButtonMaker is clicked on top of a button, or when a button is provided as a parameter to another button or a Block) is computed by sending the Button's message to the object beneath it, and using the resulting returned value.

You can create new Buttons using the ButtonMaker.

The Warehouse

The Warehouse stores Quirk objects.

Objects can be brought out of the Warehouse by shift-clicking on the Warehouse image in the World window, and selecting the object from the resulting menu.

Objects can be added to the Warehouse by sending the addToWarehouse message to the object.

The ButtonMaker

The ButtonMaker appears when the World is created. It is used to create new Buttons.

Drag the ButtonMaker (labeled makeButton) onto an object and shift-click to bring up a menu of all messages that object accepts. Select an item from the menu to create a button which sends that message.

Alternately, shift-click the ButtonMaker while it is not on top of any object to bring up a window where you can type any message name (ex. 'at:put') and create a button for that message.

The ObjectMaker

The ObjectMaker appears when the World is created. It is used to create new Objects.

Drag the ObjectMaker (labeled MakeObject) onto an object and shift-click to create a new object with the same value as that object. This is particularly useful for Buttons, since the value of a Button is computed by sending its message. Thus the ObjectMaker can be used together with one or more Buttons to create an Object in the World which is the result of one or more Smalltalk message sends.

Alternately, shift-click the ObjectMaker while it is not on top of any object to bring up a window where you can type any Smalltalk expression (ex. 'Array new: 5') and create a new Object whose value is the value of the expression.

Blocks

Blocks represent Smalltalk blocks. Blocks appear in the World as green rectangles with a square for each parameter. The squares act identically to those on Buttons, and can be used to specify directly the block parameters. Shift-clicking on a block evaluates the block using the specified parameters. You can use the ObjectMaker to convert the result into a World object by putting the ObjectMaker on the block and shift-clicking it.

The value of a block (used when the the ObjectMaker or the ButtonMaker is clicked on top of a block, or when a block is provided as a parameter to another block or a Button) is computed by evaluating the Block with the specified parameters and using the resulting value, unless no parameters are specified. If no parameter are specified (if there are no lines leading from the squares on the Block), the value of the Block is instead the value of the underlying Smalltalk block. This duality allows Blocks to serve two purposes-- they can provide easy computations when parameters are provided, and they can serve as normal Smalltalk blocks when parameters are not provided. The latter purpose might be used to supply a block as a parameter to a do: button, for instance.

The Displayer

The Displayer lets you display the value of any Object. The Displayer is created by pulling it out of the Warehouse. Creating a Displayer also creates an associated window which the Displayer uses to display. When the Displayer button is clicked, the Displayer object displays the value of the object under it. Thus, the Displayer object provides a convenient way of displaying values in the visual programming environment.


Quirk 6 was created from Quirk 5 by David Anderson, Greg Ferrar (ferrar@flowerfire.com), David Hyatt, Ying-Siong Leong, Rebecca Swick, and Sau-Loon Tong, under the direction of Dr. Ralph E. Johnson, and with help from John Brant.