BookPDF Available

Abstract and Figures

The Swarm toolkit for agent-based modelling is discussed in three stages of increasing detail. The first part provides an introductory treatment and description of Swarm. The second part provides a deeper survey of the anatomy of a swarm program. The third part goes into significantly greater detail on some elements of programming in Swarm that users are likely to enounter as they build programs with Swarm.
Content may be subject to copyright.
Swarm User Guide
Swarm Development Group
Paul Johnson
University of Kansas
Department of Political Science
pauljohn@ukans.edu
Alex Lancaster
Santa Fe Institute
alex@santafe.edu
Swarm User Guide
by Swarm Development Group
by Paul Johnson and Alex Lancaster
Published 10 April 2000
Copyright © 1999-2000 by Swarm Development Group
A User’s Guide for the Swarm Simulation System
This document began with the Swarm Tutorial presented at SwarmFests 1998 and 1999 by Benedikt Stefansson of
CASA Inc. (formerly of UCLA Department of Economics). The Swarm Toolkit is discussed in three stages of
increasing detail. The first part provides an introductory treatment and description of Swarm. The second part
provides a deeper survey of the anatomy of a swarm program. The third part goes into significantly greater detail on
some elements of programming in Swarm that users are likely to enounter as they build programs with Swarm. Users
are encouraged to explore the Swarm sample programs and to visit the Swarm home page (http://www.swarm.org),
where they can find out the latest news and join the Swarm e-mail community.
Paul Johnson’s effort on this project was supported in part by a grant from the National Science Foundation
(SBR-9709404). Paul is the primary author of the main bulk of the Guide material.
Alex Lancaster is responsible for most of the SGML-"smithing" and markup issues in DocBook (see Colophon) and
supplied additional material and text.
Licence terms for Swarm User Guide
Reproduction of this documentation requires prior copyright release in writing, from the copyright holder (the Swarm Development Group);
except for reasonable personal use or educational purposes. Reproduction for mass distribution or profit, is not permitted. The SGML source and
associated utilites needed to generate this documentation can be found in the package: userbook-0.9.tar.gz
(ftp://ftp.swarm.org/pub/swarm/userbook-0.9.tar.gz). Permission to use, copy, modify and distribute both the swarmdocs package and the
documentation it generates (that is the HTML, TeX, dvi, PostScript and RTF output), must be in accordance with the GNU General Public
Licence (http://www.gnu.org/copyleft/gpl.html) (GPL).
Table of Contents
About this Guide........................................................................................................................................9
Part I. Basic Concepts.............................................................................................................................11
1. Introduction..................................................................................................................................12
1.1. Basic Facts About Swarm................................................................................................12
1.2. Swarm is a Dynamic Platform.........................................................................................13
1.3. Prerequisites for Success with Swarm.............................................................................14
2. Programming and Simulation ......................................................................................................16
2.1. What is an Object?...........................................................................................................16
2.2. The Variety of Objects.....................................................................................................18
2.3. The Advantages of Object Oriented Programming.........................................................18
2.3.1. Encapsulation......................................................................................................18
2.3.2. Inheritance...........................................................................................................19
2.4. Discrete Event Simulation...............................................................................................20
3. Nuts and Bolts of Object-Oriented Programming........................................................................21
3.1. Multilanguage support and Swarm..................................................................................21
3.1.1. Objective C .........................................................................................................21
3.1.2. Java......................................................................................................................21
3.1.3. Why is Swarm Written in Objective C?..............................................................22
3.2. Objective C Basics...........................................................................................................22
3.2.1. The
id Variable Type ..........................................................................................22
3.2.2. Interface File: Declaration of a Class..................................................................23
3.2.3. Implementation File: Defining a Class ...............................................................25
3.2.4. C Functions vs. Objective C Methods ................................................................26
3.3. Java Basics.......................................................................................................................27
3.4. Giving Life to Classes: Instantiation...............................................................................28
3.4.1. Instantiation: Objective C Style..........................................................................29
3.4.2. Instantiation: Java Style......................................................................................30
3.5. A Brief Clarification: Classes and Protocols in Objective C...........................................30
4. The notion of a Swarm.................................................................................................................33
4.1. Primary and Auxiliary Agents.........................................................................................33
4.2. The (Swarm) OOP way...................................................................................................33
4.3. Managing Memory in Swarms........................................................................................34
4.4. What goes on in the buildObjects method?.............................................................34
4.5. What goes on in the buildActions method?.............................................................35
4.6. Merging Schedules in Swarms ........................................................................................36
5. The Graphical User Interface.......................................................................................................38
5.1. Elements of the Swarm GUI............................................................................................38
5.2. GUI Probe Displays.........................................................................................................40
3
5.3. Using the GUI Probe Display..........................................................................................42
Part II. Swarm Applications: Examples and Illustrations...................................................................44
6. The Swarm Tutorial: Reprise.......................................................................................................45
6.1. Tutorial Progression.........................................................................................................45
6.2. What Are You Supposed to Learn from the Tutorial?.....................................................46
6.3. After the Tutorial: What now?.........................................................................................48
7. Creating Objects In Swarm..........................................................................................................49
7.1. Begin at the Beginning....................................................................................................49
7.2. Detailed Look at createBegin/createEnd............................................................49
7.3. Swarm Zones and Recursive Objects Creation ...............................................................51
7.4. Using Swarm Library Objects and Header Files.............................................................53
7.5. Variations on a Theme.....................................................................................................55
7.6. How Do You Kill Off Those Poor Little Devils?............................................................56
8. Doing the Chores: set and get.................................................................................................59
8.1. Get and Set Methods .......................................................................................................59
8.2. Using Set Methods During Object Creation....................................................................60
8.3. Passing Information Around............................................................................................61
8.4. Circumventing the Object-Oriented Guidelines..............................................................63
9. Building Schedules ......................................................................................................................64
9.1. Building
Schedules..........................................................................................................64
9.2. What’s that M() Thing? ..................................................................................................65
9.3.
ActionGroups....................................................................................................................68
9.4. Activating Swarms...........................................................................................................69
9.5. What is an
Activity?.......................................................................................................70
9.6. Dynamic Scheduling .......................................................................................................71
10. Working with Lists.....................................................................................................................73
10.1. The
List Class...............................................................................................................73
10.2. Basic
List Syntax..........................................................................................................73
10.3. Lists: Managing Objects in the Model Swarm..............................................................74
10.4. Lists: Passing Information Among Levels in a Swarm Model......................................76
10.5. Lists: Organizing Repetitive Chores inside Objects......................................................77
11. Checking on a Swarm’s progress: The Observer.......................................................................81
11.1. Monitoring a Swarm......................................................................................................81
11.2. Making a clickable
ZoomRaster .....................................................................................81
11.3. Displaying Results in Graphs........................................................................................86
12. Probing and Displaying the Contents of Swarm Objects...........................................................88
12.1. What’s a Probe?.............................................................................................................88
12.2. Managing Probe Displays..............................................................................................89
12.3. How to Customize Probe Displays................................................................................91
12.4. Controlling Precision of Display...................................................................................93
4
12.4.1. Global setting of precision................................................................................94
12.4.2. Setting Precision for Individual Probes ............................................................95
Part III. Advanced Topics.......................................................................................................................97
13. Anything C can do, Swarm Can Do Better................................................................................98
13.1. Managing command line parameters.............................................................................98
13.2. Using C Functions in Swarm.......................................................................................101
13.3. Examples of Useful Functions: getInt and getDouble.......................................103
13.4. Dynamic Memory Allocation and Swarm Zones........................................................104
13.5. Dropping Unused Objects ...........................................................................................106
14. The Swarm Collections Library...............................................................................................109
14.1. Overview: the
List, Map and Array Protocols..............................................................109
14.2. Choosing between
Lists, Maps, and Arrays .................................................................110
14.3. Using Swarm
Arrays....................................................................................................111
14.4. Swarm
Maps..................................................................................................................112
14.5. Accessing Collections with Indices.............................................................................117
15. Using the Random Library.......................................................................................................119
15.1. Built-in Random Number Distributions......................................................................119
15.2. Overview of the Random Library................................................................................120
15.3. The Random Number Generators................................................................................122
15.3.1. How to use the default random generator.......................................................122
15.3.2. A list of generators in Swarm.........................................................................123
15.3.3. A note on starting seeds..................................................................................124
15.4. The Distributions in Swarm.........................................................................................125
15.4.1. Classes that adopt the ProbabilityDistribution Protocol.................................125
15.4.2. Matching generator and distribution objects...................................................125
15.4.3. Setting numerical parameters of distribution objects......................................126
15.5. How to Create Other Random Number Distributions .................................................127
16. Serialization .............................................................................................................................129
16.1. Using the
LispArchiver to manage simulation parameters.........................................129
16.1.1. Using the Standard
lispAppArchiver
.....................................................129
16.1.2. Using Custom
LispArchiver Instances...........................................................132
A. Swarm Tools......................................................................................................................................135
A.1. Web Resources for Object-Oriented Languages....................................................................135
A.2. Debugging Tips for Swarm....................................................................................................135
A.2.1. Finding bugs..............................................................................................................136
A.2.2. Preventing Bugs: Objective C....................................................................................136
A.2.3. Preventing Bugs: Java................................................................................................137
A.3. Emacs and Swarm..................................................................................................................137
A.3.1. Objective C................................................................................................................138
A.3.2. Java ............................................................................................................................138
5
B. Objective C - Swarm Style ...............................................................................................................139
B.1. Non-Conventional Techniques, And The Libraries In Which They’re Used.........................139
B.2. Zones......................................................................................................................................139
B.2.1. Zones in Principle......................................................................................................139
B.2.2. Zones in Practice........................................................................................................139
B.3. Create Phase...........................................................................................................................140
B.3.1. The Create Phase in Principle....................................................................................140
B.3.2. The Create Phase in Practice .....................................................................................141
B.4. Collections and Defobj...........................................................................................................142
C. Random Library Appendix..............................................................................................................144
C.1. Supplemental comments on random number generators .......................................................144
C.2. Usage Guide...........................................................................................................................144
C.2.1. Usage Guide for Generators ......................................................................................144
C.2.1.1. Simple generators..........................................................................................146
C.2.1.1.1. the lazy way......................................................................................146
C.2.1.1.2. using a single seed value...................................................................146
C.2.1.1.3. using a vector of seed values ............................................................147
C.2.1.1.4. antithetic values................................................................................148
C.2.1.1.5. generator output................................................................................148
C.2.1.2. Split generators..............................................................................................149
C.2.1.3. Saving and Resetting State............................................................................151
C.2.2. Usage Guide for Distributions...................................................................................152
C.2.2.1. Creating distributions....................................................................................152
C.2.2.1.1. the lazy way:.....................................................................................152
C.2.2.1.2. Without default parameters, using a simple generator .....................153
C.2.2.1.3. Without default parameters, using a split generator.........................153
C.2.2.1.4. With default parameters, using a simple generator...........................154
C.2.2.1.5. With default parameters, using a split generator..............................154
C.2.2.1.6. You may reset the default parameters this way, as often as you like154
C.2.2.1.7. You can obtain the current values of parameters..............................154
C.2.2.1.8. You can reset the variate counter and other state variables this way155
C.2.2.1.9. Finally, we have the InternalState protocol methods........................155
C.2.2.2. Saving And Restoring State ..........................................................................156
C.3. Advanced Usage Guide..........................................................................................................156
C.3.1. Choosing a Generator ................................................................................................156
C.3.1.1. Choosing A Generator...................................................................................156
C.3.1.2. Strategy For Using Random Generators .......................................................157
C.3.1.3. Generator Quality..........................................................................................158
C.3.1.4. More generator data ......................................................................................161
C.3.2. Default Generators for the Distributions....................................................................163
6
C.3.2.1. Random Library: Default Generators............................................................163
C.3.2.2. Utility Generator And Distributions..............................................................164
C.3.3. Random Library Test Programs.................................................................................164
C.4. Resources for random number generation..............................................................................166
C.4.1. Generators..................................................................................................................166
C.4.2. Distributions...............................................................................................................166
C.4.3. Useful Web Sites........................................................................................................167
Bibliography.........................................................................................................................167
Bibliography...........................................................................................................................................170
Index........................................................................................................................................................172
Colophon.................................................................................................................................................175
7
List of Tables
C-1. Random Library: Generator Statistical Tests...................................................................................158
C-2. Random Library: Generator Data....................................................................................................161
C-3. Random Library: Default Generators..............................................................................................164
List of Figures
2-1. Agent-based modeling........................................................................................................................16
2-2. Interface vs. Implementation..............................................................................................................19
3-1. Objective C Basics .............................................................................................................................23
4-1. Nested hierarchy of Swarms...............................................................................................................36
4-2. Swarm virtual computer.....................................................................................................................37
5-1. Line graphs (in this case, a time series)..............................................................................................38
5-2. Histograms..........................................................................................................................................38
5-3. Rasters of discrete two-dimensional data...........................................................................................39
5-4. Example
ProbeMaps for the tutorial ModelSwarm and ObserverSwarm ..............................................39
12-1. Combining two
VarProbe and one MessageProbesonaProbeDisplay..............................................88
B-1. Schematic of proto-object creation..................................................................................................140
List of Examples
3-1. Objective C class................................................................................................................................24
3-2. C vs Objective C.................................................................................................................................27
3-3. Java class ............................................................................................................................................27
12-1. Generating a
probeMap
.................................................................................................................91
12-2. Non-verbose
probeMap
creation...................................................................................................93
12-3. Global setting precision in
HeatbugObserverSwarm.m .......................................................................94
12-4. Setting precision for individual probes in
HeatbugModelSwarm.m:....................................................95
14-1. Maps and keys................................................................................................................................112
16-1. Using a standard
lispAppName
instance....................................................................................130
16-2. Creating a Lisp parameter file with an alternate name...................................................................132
8
About this Guide
This Guide presents an overview of the Swarm simulation toolkit. It is intended to be used in conjunction
with other materials, which include the sample programs and tutorials provided by the Swarm team and
the Swarm Documentation Set. Since this is a user guide, it is intended to be less formal and not so
encyclopaedic as the Reference Guide to Swarm
(http://www.santafe.edu/projects/swarm/swarmdocs/refbook/refbook.html).When there is any doubt, the
Reference Guide (and the source code itself) is the final, most appropriate, authority.
Part I. An overview of Swarm and a brief primer on Swarm object-oriented programming using
Objective C and Java.
At the time of writing only Part I has been written from a joint Objective C/Java perspective,
subsequent Parts assume you are using the Objective C version of Swarm, a limitation we hope
to rectify in future versions of this Guide
Part II. A reprise on the Swarm tutorial package, explaining in-depth various non-obvious features of
Swarm coding. As previously noted, the present this only covers the Objective C version
Part III. Advanced Topics: as you might guess, not for the uninitiated, these are important topics you
will need to know to become a competent in using the Swarm libraries.
The inspiration for this Guide was provided by Benedikt Stefansson <
benedikt@post.com>, who
prepared a series of lectures for the 1998 and 1999 SwarmFests. Benedikt generated a series of slides and
illustrations and many of them have been adapted for this Guide. He has also provided help in the form
of sample code and advice about many topics.
Conventions used in this document:
Note
Interesting fact(s), not necessarily of vital significance to the user.
Tip
A coding tip, a suggested convention to adopt or suggested usage.
9
About this Guide
Important
Important fact(s) you should know before proceeding to the next section.
Caution
A note of caution, generally regarding a changed usage, deprecated functionality or other
compatibility issue.
Warning
Vital information that a user needs to be aware of before proceeding.
10
Part I. Basic Concepts
Chapter 1. Introduction
The Swarm project was started in 1994 by Chris Langton, then at Santa Fe Institute
(http://www.santafe.edu) (SFI)in New Mexico. It is currently based at the non-for-profit organization,
Swarm Development Group (http://www.swarm.org)also based in Santa Fe, New Mexico. The aim was
to develop both a vocabulary and a set of standard computer tools for the development of multi-agent
simulation models (so-called ABMs, short for Agent-Based Models). Armed with this framework,
researchers are able to focus on the substance of the modeling task, avoiding some of the complicated
details of computer coding.
The Swarm project has benefitted from the contributions of many programmers, including Roger
Burkhart, Nelson Minar, Manor Askenazi, Glen Ropella, Sven Thommesen, Marcus Daniels, Alex
Lancaster, Vladimir Jojic, and Irene Lee.
1.1. Basic Facts About Swarm
Swarm is a collection of software libraries which provide support for simulation programming. Among
the most prominent features are the following.
Swarm Code is Object-Oriented. The swarm libraries are written in a computer language called
"Objective-C", a superset of the C language. Objective-C adds the ability to create software "classes"
from which individual instances can be created. These instances are self-contained entities, and the
terminology of object-oriented programming turns out to be very well suited to discussions of
agent-based models.
Swarm Programs are Hierarchical. Most swarm applications have a structure that roughly goes like
this. First, a top level–often called the "observer swarm"–is created. That layer creates screen displays
and it also creates the level below it, which is called the "model swarm". The model swarm in turn
creates the individual agents, schedulestheir activities, collects information about them and relays that
information when the observer swarm needs it. This terminology is not required by Swarm, but its use
does facilitate it.
Swarm Provides Many Handy Tools. As we shall see in later sections, the Swarm libraries provide a
number of convenient pieces of code that will facilitate the design of an agent-based model. These
tools facilitate the management of memory, the maintenance of lists, scheduling of actions, and many
other chores.
Users build simulations by incorporating Swarm objects in their own programs. Users are encouraged to
study a number of tutorial examples in order to make full use of the Swarm libraries and the strategy of
modeling that inspires them.
12
Chapter 1. Introduction
1.2. Swarm is a Dynamic Platform
Swarm is free software (http://www.gnu.org/philosophy/free-sw.html)
1
. The current Swarm distribution
is effectively
2
released under the GNU General Public License (GPL
(http://www.gnu.org/copyleft/gpl.html)).The free software model of software development is
particularly effective for a tool like Swarm, for both theoretical and practical reasons:
Complete Observability. With full source available, if necessary, the modeller can always track the
execution of the simulation right down to the operating system level. This is very important for
reproducibility, and ultimately allows you to go about proving (in an abstract mathematical sense) a
simulation’s ‘correctness’.
Developer Mind-Share. More practically, Swarm is open source so that we can harness developer
mind-share: more technically minded users can identify bugs, write patches, implement new features
generally contribute to the evolution of Swarm. These are all identical to the reasons that the
GNU/Linux operating system has grown so fast (and is so robust) [DiBona et. al. 1999]. As Swarm
grows, more programmers, and technically curious modellers are becoming involved in the project.
The development work is being done by the Swarm Development Group (http://www.swarm.org),
located in Santa Fe, New Mexico. (The Swarm project relocated from the SFI at the end of October
1999). Their results are periodically released on the Internet and users have access to the source code.
The creators fully intended for users to take the code, experiment with it, and propose changes and
enhancements. This open source strategy is designed to capture the contributions of a lively research
community. When users make improvements in the libraries, they are encouraged to announce them to
the community and make them available. As a result of the interaction of the community and the Swarm
team, the Swarm libraries are constantly being revised.
To get an idea of how much things change, consider the brief history of the project. Swarm was
originally intended for Unix operating systems that support the X Windows System. The first beta
version of Swarm was released in 1995. In January 1997, version 1.0 was released to the public. It would
run on Solaris and Linux operating systems. Quickly after that, minor releases followed that opened up
Swarm to the DEC Alpha platform and other flavors of Unix. In April 1998, the reach of Swarm again
broadened, as version 1.1 was released and, with the help of the Cygnus Win32 package, Swarm could
be used on the Microsoft Windows 95/NT (and now 98) operating systems. In late 1999 the Swarm
1. sometimes referred to as "open source" source software, see the Open Source Definition
(http://www.opensource.org/osd.html)
2. The core Swarm libraries are currently released under the LGPL (http://www.gnu.org/copyleft/lgpl.html), but the standard
binary distributions generally include many GPLed support components, which effectively mean that Swarm is GPLed.
13
Chapter 1. Introduction
releases 2.0 and 2.0.1 introduced a Java layer for Swarm to enable Java programmers to access Swarm
libraries and enabled the export of data through the HDF5 binary data format from NSCA.
Because Swarm does grow and change as a result of the complex interaction within a research
community, its precise path for development is not predictable. Current priorities for the Swarm team at
the SDG include the further generalization of Swarm to be useful on a broader array of platforms and in
conjunction with additional computer languages. Prototype XML and Scheme layers for Swarm have
been tested, for example.
1.3. Prerequisites for Success with Swarm.
Swarm was originally conceived as a set of standardized methods for the design of multi-agent
simulation models. One need not be a highly accomplished computer program to user the Swarm
libraries. In fact, as the installation process for Swarm becomes increasingly streamlined, it is quite easy
for anyone with suitable hardware to test some of the sample applications. For people who have
Windows 98/NT or Linux operating systems, compiled versions of the Swarm libraries are available and
installation is quite painless
However, it is not easy to create new Swarm applications. Doing so requires the creation of a computer
program. While one need not be an expert programmer, one must have a rudimentary understanding of
vital computing concepts. The required knowledge will vary with the sort of model that one is intending
to create, of course, but, at the bare minumum, users must have:
a basic understanding of computer programming
and, at the time of writing, either of the two object-oriented programming languages, Java or
Objective C
3
Java is a straightforward language to learn, and has the advantage of being a mainstream, well-supported
language in terms of both tools and documentation. Objective-C is, well, truly elegant and fun to use and
people who know C say it is fairly easy to learn (C is also a highly useful language and it is relatively
easy to learn).
People who have not done computer programming will thus need to do some background preparation
before they try to make a serious effort at building a Swarm model.
If you choose to implement your models in Objective C, we suggest that the first step is to find one of the
many elementary guides to computing with C, such as The C Programming Language, [Kernighan &
3. in the Objective C case, an understanding of the C computer language, is also helpful, since Objective C is a superset of the C
language
14
Chapter 1. Introduction
Ritchie, 1988]. Written by the authors of C, Brian Kernighan and Dennis Ritchie, it is a truly readable
and informative manual that all users ought to investigate.
If you choose to implement your models in Java, there are literally thousands of introductory
programming-in-Java resources on the market, both in paper and electronic form (see Section A.1 for
some starting points).
A manual with examples and exercises is vital. These will teach the basics about writing code and
compiling it into programs.
The Objective-C language is best learned from the online book Object Oriented Programming and the
Objective C Language [NeXT, 1993].
15
Chapter 2. Programming and Simulation
Swarm is designed to help researchers build models in which low-level actors interact (often called
"complex systems"). The researcher has to give content to "agents," possibly by thinking of them as
honey bees, investors, trees, or (the ubiquitous) "bugs." One research goal is to discern overall patterns
that emerge from these detailed behaviors at the individual level.
Figure 2-1. Agent-based modeling
Bottom up modeling
Organizations of agents
Animate agents
Data
Observer
Inanimate agents
Object oriented programming is ideally suited to represent models of this sort. As we shall see, the
objects are self-contained. Objects may be designed to convey information (answer questions) from other
objects and also they can retain, categorize, and summarize information.
2.1. What is an Object?
16
Chapter 2. Programming and Simulation
A careful study of either of the object-oriented programming languages (Java or Objective-C) is required
before any significant progress can be made in building a Swarm model. The material presented here is
intended as a summary or reminder of such a study, rather than a substitute.
An object consists of two kinds of information
Variables. The list of variables summarizes the "state" of the agent–its age, wealth, its ability, and so
forth. These variables may be of any type that is allowed in C, such as integer (
int), floating-point
number (
float), an array, a pointer, and so forth. These variables might also be of type id, which
means they might also be instances of classes, and;
Methods. Methods determine what the object can do. Typically, there will be methods that receive
information from the "outside world", methods that send messages to the outside, and methods that
process information.
Variables and methods are given meaningful names, so code is easier to read. The custom is to run words
together to make meaningful tags, such as goToStore or goHome.
Objects are created through a process called "instantiation." Put tersely, code is written in "classes" and
then objects are created as instances of their classes. The varibles that an instance, or object, keeps inside
itself are called "instance variables". The information contained inside instance variables is available to
all methods inside that object. If one of the methods in an object needs to have "private" informationthat
is not available to other methods in the object, then "method variables" can be created to hold that
information.
In both Objective-C and Java, the term message is often used to refer to an instruction that tells an object
to carry out one of its methods. (For readers more familiar to C++, the term member function, refers to
the same thing as the term method). Here is an example of a message that tells an object known as
bobDole
to execute its method runForPresident.
Objective C example Java example
[bobDole runForPresident]; bobDole.runForPresident();
In Objective C, some methods have parameters that specify details and they are added with colons (:)
after the name of the method to be executed. In Java, the entire method name is listed before the
parameters are given
1
. For example, if the method runForPresident required additional
parameters, such as the year and the name of the runningmate, then the message might look like so:
Objective C example Java example
1. In our Java example we use a dollar sign ($) inline between the parts of the method that are separated in the Objective C case.
This is purely a convention introduced to stay as close to conventions adopted by the Java Swarm libraries. This is in no way
enforced by the Java language itself.
17
Chapter 2. Programming and Simulation
Objective C example Java example
[bobDole runForPresident:2000 with:
RossPerot];
bobDole.runForPresident$with (2000,
RossPerot);
We will have plenty of additional examples in the rest of the Guide.
2.2. The Variety of Objects
In a Swarm model, there can be many types of agents (see Figure 2-1) Obviously, if a model is going to
describe honey bees, it has to have honey bee agents. It will also have objects that represent other actors
in the model, and not all other actors are animate. There might be other insects and bears, but there will
also be objects that represent the environment (trees, rainstorms, etc). The model will typically also have
objects that facilitate the modeling process and collect information about the simulation and relay it to
the researcher.
2.3. The Advantages of Object Oriented
Programming
Object oriented programming (OOP)is well suited to describe autonomous agents,so it should have
appeal to scientists and modelers on that basis alone. However, that is not the end of the subject. OOP it
has virtues that are equally important to computer programmers. OOP, as it is found in Objective-C, is
not exactly the same as OOP in C++ or Java, but these languages have some significant features in
common. The features we emphasize here are encapsulation and inheritance.
2.3.1. Encapsulation
The values of the variables inside an object are private, unless methods are written to pass
that information outside of the object.
This has both substantive and practical implications. The substantive importance is that the
representation of an individual actor now presumes that the actor is a self-contained entity and that other
actors do not automatically have access to all information inside that actor. Like humans, objects have to
take effort to convey information to each other about their internal states. The practical advantages of
encapsulation, however, are just as important. Computer projects can be broken down into separable
components (code for the classes) and when the code is finished, the details of what goes on inside each
object may not be important to the programmer. For example, if an object
groceryStore
can respond
to an message takeMoney, and it gets the job done, we might not care how it does it.
18
Chapter 2. Programming and Simulation
Figure 2-2. Interface vs. Implementation
User only has to be familiar
with the interface of an object,
not it’s implementation
Objects hide their
functions and data
This is commonly referred to as the separation of "interface" from "implementation." While the interface
declares what methods the object can execute, the implementation may remain hidden (see Figure 2-2),
the user only has to be familiar with the interface of an object, not it’s implementation
2.3.2. Inheritance
Each subclass inherits all variables and methods of its superclass.
Inheritance works because code for each class designates that class as a subclass of a superclass. For
example, in the GNU Objective-C compiler used in the Swarm project, there is a most basic class,
"object". From the object class, the Swarm libraries create subclasses, and subclasses are created from
them, and so forth until the programmer in a swarm project wants to create a new class of actors that is
subclassed from
SwarmObject. If the programmer needs to create several varieties of that class, there is no
need to totally rewrite each one. Subclasses can be created that have as a base all variables and methods
of the class but then new methods and variables can be added as well.
When a method, say takeMoney, exists in a class
Store, and then a subclass is created, say
GroceryStore, then all objects instantiated from the subclass will respond to takeMoney. If the
programmer wants to rewrite the takeMoney method for
GroceryStores, however, then the method can
19
Chapter 2. Programming and Simulation
be revised inside the code for the subclass and then all instances of the
GroceryStore class will respond
to takeMoney in that specialized way. The method inside the
GroceryStore subclass will override the
super-class’s definition of the method.
2.4. Discrete Event Simulation
A Swarm simulation proceeds in discrete time steps. Objects are created and then interact according to a
scheduling mechanism. As the simulation proceeds, the agents update their instance variables and they
may be asked to report their state to the observer swarm layer of the simulation.
The modeling process in Swarm, then, is quite different from simulation modeling in a non-object
oriented language, such as Fortran or Pascal. These so-called "procedural languages" do not allow the
modeler to take advantage of reusable classes through inheritance or the preservation of data allowed by
encapsulation. Here’s an example of a simulation in a procedural language:
Procedural language pseudo-code
1. get parameters
2. initialize
2
3. for 1 to timesteps do:
a. for 1 to num_agents do:
i. agent-i-do-something
3
b. show state
4
4. quit
2. Generally sets up data structures and support for output.
3. Here must provide data structure to save agent’s state and implement behavior
4. Implementation of output often left to the programmer
20
Chapter 3. Nuts and Bolts of
Object-Oriented Programming
3.1. Multilanguage support and Swarm
Swarm is not a single application that is ‘turned on’. Swarm is a set of libraries that you can pick and
choose features from. In order to use the Swarm libraries, it is necessary to create or use code that calls
Swarm features.
3.1.1. Objective C
Until recently, there was one way to use Swarm features: write and compile a program in Objective C.
This is a flexible and way to write a model using Swarm. Objective C models tend to have good
performance because they are compiled by a native code optimizing compiler, namely GCC.
Objective C was created by Brad Cox [NeXT, 1993]. The aim was to create an elegant, object-oriented
extension of C in the style of the Smalltalk language [Goldberg & Robson, 1989]. Objective C was used
most intensively in the design of the NeXT computer operating system, which is now owned by Apple
and is basis of Apple’s runtime environment WebObjects.
3.1.2. Java
Since Swarm 2.0, modellers can use Java. For new users of Swarm, writing models in Java is
considerably harder to get wrong. Java is also a more attractive languages for new users to learn since it
is a popular language that has benefits outside of Swarm modelling.
Java was created by Sun Microsystems, initially to provide a platform-independent layer or interface for
embedded devices (such as set-top boxes for digital television) and was originally known as Oak. With
the advent and growth of the world wide web from 1992 onwards, Oak was renamed Java and redirected
at the market created by the web. “Write once, run anywhere” was the motto of the original Java
developers, the idea being to create an abstraction layer between the programmer and the underlying chip
architecture (ix86, Sparc, Alpha) known as a virtual machine (or interpreter)
1
1. In theory all programmers needed to do was to write so-called "pure Java" code that targeted the virtual machine, whilst the
virtual machine itself only needed to ported once to each new architecture or chip, by the maintainers of the language itself
(rather than the applications programmer). With certain caveats, this has been largely realized, and Java is now a robust
platform that is used in both web client GUI programming (applets) as well as server applications (servlets). Use of Java does
come at a cost, the extra step of translating the virtual machine instructions into the native machine instructions at run-time
does have a performance penalty at run-time, but with the advent of so-called native compilers which do this translation at
21
Chapter 3. Nuts and Bolts of Object-Oriented Programming
The purpose of the Java layer of Swarm (actually it is a system that is potentially extensible to other
languages such as Scheme or C++) is to mirror the protocols of the Swarm libraries as Java interfaces.
For more details on the ongoing work of integrating Swarm with other languages and simulation
technologies such as XML and Scheme, see the paper Integrating Simulation Technologies With
Swarm [Daniels, 1999].
3.1.3. Why is Swarm Written in Objective C?
Since Objective C is not currently a mainstream programming language, it is natural to ask why the
Swarm project chose Objective C. There are a number of reasons:
Objective C is easier to learn. Objective C takes the familiar C language and adds a few simple
elements. Objective C does not allow overloading or multiple inheritance of classes (although the use
of protocols enables this, to an extent)
Objective C allows run-time binding. In contrast to other languages which check the match between
the receiver of a command and its ability to carry out the command when a program is compiled,
Objective C leaves that matching exercise until the program is running. This means, for example, that
one can have a program that builds a list of objects and then sends a message to each one. In Objective
C, the compiler won’t worry about which type of object is in the list. The advantage, conceptually, is
that one can put commands in their code without knowing the precise identity of the receiver, so code
can be written to allow an environment and set of objects to change and evolve. The disadvantage, as
critics of run-time binding will quickly point out, is that programs crash when an object recieves a
message and it does not have the method that it is being told to execute. The organization of Swarm
into protocols reduces the risk of these crashes, however, because the compiler does check and issue a
warning if a method is not implemented in a class that advertises a certain protocol.
3.2. Objective C Basics
3.2.1. The id Variable Type
compile-time (rather than at run-time), many applications can, in principle, run much faster than they currently do.
22
Chapter 3. Nuts and Bolts of Object-Oriented Programming
The variable type that is added by Objective C is
id. It is the default type for objects in Objective C.
Think of this as a special variable type (which is actually a pointer to a special data structure - namely the
object)
All objects can refer to themselves by using the label
self
. This is necessary if, in the code that defines
the object, the programmer wants to make the object execute one of its methods. For example, suppose
an object has a method called updateRecords. If a command
[self updateRecords];
is received, then the updateRecords command will be executed, presumably to cause the updating of
instance variables.
All objects can refer to superclass by the name
super
. For example:
[super updateRecords]
3.2.2. Interface File: Declaration of a Class
If you look in a directory where some Objective C Swarm code resides, you will see files in pairs, such
as
ObserverSwarm.h and ObserverSwarm.m, ModelSwarm.h and ModelSwarm.m, and so forth. The "h" files
are the interface files (commonly called header files), while the "m" files are the implementation files
23
Chapter 3. Nuts and Bolts of Object-Oriented Programming
Figure 3-1. Objective C Basics
@interface Bug : SwarmObject {
int xPos, yPos;
int worldXSize, worldYSize;
id foodSpace;
}
-setX: (int) x Y: (int) y;
-step;
@end
Super class
Sub classes
Instance
Variables
Methods
As illustrated in Figure 3-1, the interface declares the name of the class and the name of its superclass.
Then it gives a list of variable types and names enclosed by braces ({}), and then the names of the
methods that the class can implement are listed. The variables defined in this list can be used by any of
the methods defined for the class. (These are often called "ivars", short for instance variables.)
Example 3-1. Objective C class
(1)@interface Bug(2) : SwarmObject(3)
{
int xPos, yPos;
int worldXSize, worldYSize;(4)
id foodSpace;
}
- setX: (int) x Y: (int) y;(5)
- step;(6)
- (return_type)look: (direction_type) d;(7)
@end
24
Chapter 3. Nuts and Bolts of Object-Oriented Programming
(1) Declarations of instance variables and methods
(2) Sub class
(3) Super class
(4) Instance Variables
(5) declares method called set that takes two arguments
(6) declares a method called step.
(7) declares a method called look that takes one argument of type
direction_type and returns an
argument of type
return_type.
3.2.3. Implementation File: Defining a Class
Each implementation file–the .m that parallels the .h – must import its header file. For the header file
described above, called
Bug.h, for example, the implementation looks like:
#import "Bug.h"
@implementation Bug
- setX: (int) x Y: (int) y
{
xPos = x;
yPos = y;
return self;
}
- step
{
// body
return self;
}
- (return_type)look: (direction_type)d
{
return_type returnval;
// body of method
return returnval;
}
This example shows a number of important features. First, note that the method look specifies a return
type, (
return_type). In this example,
return_type
would have to be replaced by a variable type, such
as
int, float, or whatever, and
returnval
would have to be a variable of that type. When that method
is called, the receiving code must be able to accept a return of that type. In contrast, the method step
25
Chapter 3. Nuts and Bolts of Object-Oriented Programming
does not specify a return type. That means the default type,
id, is returned. The code that calls this
method must be consistent with that return type.
The
return self command is used for two types of situations. Suppose the method is not intended to
create any output, but rather it changes some instance variables. For example, suppose there is some
program that creates an instance of
Bug called
aBug
. Then that object is sent this message:
[aBug step]
In such a case, the code that calls that method does not expect anything back from it (except itself).
Rather than fuss with
void as the return type, as one might in C, one can simply return
self
.
In another case, one might actually intend to return the object to a list or another object. In such a case,
return self will also be appropriate. If one is making a list of collected bugs, for example, then the usage
of
return self in that method will give back
aBug
id to the calling program. To be perfectly concrete
about it, suppose the calling code has a list called collectedBugs. Then using the addLast
notation from the Swarm collections library, the command to add
aBug
to the list after being collected
might look like this:
[collectedBugs addLast: [aBug look:
aDirection]];
3.2.4. C Functions vs. Objective C Methods
For readers who are already familiar with C, perhaps a comparison of C functions against Objective C
methods is in order. Since Objective C is a superset of C, an Objective C method can include any valid C
commands. A method can return any type that a C function can return, and in addition it can an id
(which, strictly speaking, is a pointer to an object).
In the abstract, an Objective C method has this structure:
- (type)name: (type)arg1 argName2: (type)arg2
{
(body)
return returnval;
}
In comparison, a C function would look like this:
(type)name((type) arg1,(type) arg2))
{
(body)
return returnval;
}
26
Chapter 3. Nuts and Bolts of Object-Oriented Programming
The code in body of an Objective C method can be exactly the same as in C. The two languages are
compared side-by-side in the following example, which describes how a function rand_move() might
compare to a method rand_move:. Of course, each of these assumes there are other functions and
variables that can be accessed, but the contrast in style should be informative.
Example 3-2. C vs Objective C
C Objective C
void rand_move(int i) { int tmp_loc; do{
tmp_loc=get_rand_loc(); }
while(val[tmp_loc]!=0); val[location[i]]=0;
val[tmp_loc]=i; }
- rand_move: p { id loc; do{ loc=[self
getRandLoc]; } while([world at: loc]!=nil); [p
moveTo: loc]; return self; }
3.3. Java Basics
One of the most obvious and immediate differences between Objective C (and incidentally C++) and
Java, is that Java does not partion classes into "declarations" (header files) and "implementations"
(implementation files). All information for any Java class is contained in a single
.java file.
Perhaps the best way to illustrate this is to consider the Java equivalent of the previous Objective C
Example 3-1.
Example 3-3. Java class
(1)public class Bug(2) extends SwarmObject(3)
{
int xPos, yPos;
int worldXSize, worldYSize;(4)
FoodSpace foodSpace;
public Object setX$Y (int x, int y)(5)
{
xPos = x;
yPos = y;
return this;
}
public Object step()(6)
{
// body of step() code
27
Chapter 3. Nuts and Bolts of Object-Oriented Programming
return this;
}
public return_type look(direction_type d)(7)
{
return_type returnval;
// body of look() code
return returnval;
}
}
(1) Complete class defintion
(2) Sub class
(3) Super class
(4) Instance Variables
(5) declares method called set$Y() that takes two arguments
(6) declares a method called step() takes no arguments.
(7) declares a method called look() that takes one argument of type
direction_type and returns an
argument of type
return_type.
One important distinction to notice is that Java does not have a notion of an id or "generic" data type. All
variables must be assigned a type, in the above example the
foodSpace
instance variable is declared as
being of type
FoodSpace. This is because Java is a strongly typed language. The compiler checks all types
of all variables to ensure all receiver objects respond to the messages that are sent to them by the
programmer. Most of the rest of the other differences between the Objective C and Java examples given,
lie almost purely in deviations of syntax. Here are a few obvious ones (this list is by no means exhaustive
and the reader is encouraged to consult their Java or Objective C reference manual for all the detailed
syntax):
In Objective C, method names and the parameters are interspersed, whilst in Java, the entire method
name is given before the parameters.
In Java
self
is referred to as
this
(
super
retains its meaning and syntax in both languages).
3.4. Giving Life to Classes: Instantiation
After the code is written to implement the class (with .h and .m files for Objective C and .java in the
Java case), there is still work to be done. Instances of the class must be created. The creation of instances
28
Chapter 3. Nuts and Bolts of Object-Oriented Programming
of a class is one of the specialized features of Swarm. Since the instantiation process can be sometimes
different from the that described in the Objective C and Java literature, it is worth some special attention.
The creation of the substantively important objects is often handled in the model swarm. This process
uses the specialized memory management and object creation code in the Swarm library.
3.4.1. Instantiation: Objective C Style
The objects that represent the actors in a simulation–the substantively important entities–are usually
subclassed from the
SwarmObject class. The "inheritance hierarchy" that leads to the class SwarmObject
passes through classes that allow the creation and deletion of objects from a simulation. Objects are often
created by a pair of "bookend" commands, createBegin and createEnd. This is not part of the
Objective C syntax. Rather, it is unique to Swarm.
Suppose the
Bug.h and Bug.m files from previous exist, and one wants to create an instance of that class.
In a file
ModelSwarm.m, one would typically have a method called buildObjects, which is usually a
method that houses all object creation. For example:
// Excerpt from ModelSwarm.m that creates a Bug instance
#import "Bug.h"
// {other imports and code that defines schedules, etc}
- buildObjects
{
id aBug;
bug = [Bug createBegin: self];
// commands that set permanent features of the agent can apppear here
bug = [Bug createEnd];
}
The class’s "factory object", Bug, is told to create an object in a memory zone that is provided by
ModelSwarm (ModelSwarm is the
self
.). Then the object
aBug
is instructed to finish the creation process,
after optional commands are added to define the features of the object (typically, to set permanent
structural aspects of the class). Many of these subtleties are explained in depth in later sections (see also
Appendix B).
Object instances need not be created by the createBegin/createEnd pair. Objects can often be
created by a simple create command
2
.
aBug = [Bug create: self];
In code written for older versions of Swarm, one will often see a slightly different syntax in
ModelSwarm.m:
2. For example, the Swarm collections library includes a class called List, which is most often created this way.
29
Chapter 3. Nuts and Bolts of Object-Oriented Programming
aBug = [Bug create: [self getZone]];
In Objective C, this usage is still valid, although it is deprecated. Since now the objects of type Swarm,
like the model swarm itself, are memory zones, there is no need to get a zone in which to put the bug.
Rather, the bug can be put in the zone that is provided by the model swarm itself.
3.4.2. Instantiation: Java Style
For most stock objects created in application Java code (including user-created Java classes), the entire
createBegin/createEnd apparatus can be dispensed with. Java uses the term constructor for the
method that creates an instance of a class. The Java interface to the Swarm libraries have "convenience"
constructors which essentially bracket the entire set of create-time messages in a single call to the
constructor (or call the constructor with no arguments as in the present case). The simplest method to
create a Java
Bug object is to invoke the following:
aBug = Bug (this.getZone());
This is equivalent to the final Objective C example given in the last section. In summary here is the
comparison:
Objective C example Java example
aBug = [Bug create: [self getZone]]; aBug = Bug (this.getZone());
Note that the explicit create: method in the Objective C case, is made implicit in the Java case.
It is still possible to use the create and createBegin/createEnd apparatus in Java, but due to
Java’s strongly-typed nature, it can require considerably more coding overhead than in Objective C,
and will be left to later version of the Guide.
3.5. A Brief Clarification: Classes and Protocols in
Objective C
There is one additional complication that readers should be aware of. Objective C allows the creation of
entities called protocols. A protocol, as readers will recall from their study of Objective C, is a list of
methods that an object is able to execute. Swarm is structured by protocols, which means that there are
lists of methods assigned to various names and classes inside the library "adopt" those protocols and then
implement the methods listed in the protocols. Hence, in the Swarm Reference materials present the
libraries as a collection of classes, each of which adheres to a given set of protocols.
30
Chapter 3. Nuts and Bolts of Object-Oriented Programming
To the Swarm user, the distinction between class and protocol is not vital most of the time. The most
important Swarm protocols, such as the type
Swarm (from objectbase/Swarm.h)orSwarmObject (from
objectbase/SwarmObject.h), can be used as if they were classes. In the Swarm Reference Guide, there is
a list of all protocols. The protocols that adopt the
CREATABLE protcol are the ones that users can use as if
they were factory objects. For example, the
EZGraph protocol adopts the CREATABLE protocol, so when
the user needs to create an instance, so the observer swarm file can use the EZGraph to create graphs.
Almost all of the Swarm protocols adopt the CREATABLE protocol, so they can be used as if they were
classes from which users subclass to make model swarms or individual agents. It should not matter to the
user that these are abstract defined types that have adopted protocols (taken on the obligation to
implement methods listed in protocols). The class
SwarmObject, for example, adopts protocols Create and
Drop as well as CREATABLE. This means that the user can act as if there is a class called SwarmObject,
and that the SwarmObject will be able to respond to class methods like createBegin, and that
instances created by SwarmObject will be able to respond to createEnd, drop, or any other method
that is listed in a protocol listed by SwarmObject.
One of the principal advantages of protocol usage is that there will be compile-time warnings if the
user’s code tries to send a "bad message" to an object. If a message tells an object to goOutside, and
none of the protocols adopted by that agent have a method called goOutside, then the compiler will
warn the user about it. In a crude way, adopting a protocol is like advertising that a class can do certain
things, and the compiler enforces a ‘truth in advertising’ policy. If the compiler flags include -WERROR,
causing all warnings to be treated as errors, then these warnings will stop the compilation.
The fact that many of the important components of the Swarm library are organized as protocols can,
however, be important in some notation. Early versions of Swarm had less emphasis on protocols than
the current version. As a result of the introduction of protocols, usage conventions have changed. In
Swarm, there is a class
List that can be used to create collections. In the "old days" of Swarm, one would
create a statically typed object of class
List, as this code indicates:
List * listOfPuppies;
listOfPuppies=[List create: [self getZone]];
Swarm no longer allows users to statically allocate objects in this way. This code will make the compiler
crash, because there is no class inside Swarm called List, there is only a protocol. The compiler will fail,
and the user will get a vague warning about a parse error in the vicinity of the List usage.
We know from the Swarm Reference Guide that the
List protocol advertises that it adopts the CREATABLE
protocol, so the mistake is not in the usage of List to create the listOfPuppies. Rather, the mistake is in
the declaration of the listOfPuppies itself. If one needs to define a variable
listOfPuppies
that has
the properties of a
List class item, the recommended approach is to create a variable of type id and
indicate the protocols adopted by that object in brackets:
id List listOfPuppies;
listOfPuppies=[List create: [self getZone]];
31
Chapter 3. Nuts and Bolts of Object-Oriented Programming
It is also legal to define listOfPuppies as a generic object, as in
id listOfPuppies;
listOfPuppies=[List create: [self getZone]];
This usage is legal, and the program should compile without difficulty. The only shortcoming is that the
user will not be warned if the listOfPuppies object is sent any inappropriate messages within the
program. When these inappropriate messages are sent during the run, then the program will crash,
possibly with a message that the object listOfPuppies does not respond to the message it was sent.
Since almost all of the important pieces of functionality in the Swarm library are now written in the
protocol format and are CREATABLE, these details may be important. However, these details do not
significantly change the way applications are designed. Swarm entities can still be treated as classes.
32
Chapter 4. The notion of a Swarm
As explained in an earlier section, Swarm is designed for hierarchical creation of computer objects. The
observer swarm object is created first, and it creates a user interface and it also instantiates the model
swarm, and the model swarm then creates levels below and schedules their activities.
One of the original intentions of the Swarm project was to give users the ability to create high quality
code with a minimum of fuss. The Swarm library creates a sequence of classes that accumulate and
refine the ability to create simulation objects, manage memory for them, and schedule their activities.
4.1. Primary and Auxiliary Agents
Terminology can cause confusion because computer programmers may use the term "agent" in a way
that befuddles scientists. To the scientist, the term agent refers to a theoretically important entity that is
modeled by a simulation. To a programmer, the term agent is usually broader, something like object. As
a result, there is sometimes slippage in a discussion of "agent-based modeling" because an understanding
of the term agent is not shared.
We intend to finesse this (big surprise!) by creating terminology for two kinds of agents. This separation
of agents into primary and auxiliary groups is created solely for discussion in this manual. The idea is
that primary agents are the ones that the research sets out to model in the first place. They are described
in a theory, they have substantive importance. Usually in this sense we have representations of important
"actors" and one or more objects to represent the world in which they interact.
To the surprise of most new users, it is often also necessary to create auxiliary agents that facilitate the
work of the primary agents. For example, in a model of majority rule voting, one can have primary
agents like voters and candidates. There may be a need for an auxiliary class called
Counter, a class that
can spawn objects that can be used to tally the votes that are cast.
In most cases, when we talk about multi-agent systems, we are referring to the primary agents.
4.2. The (Swarm) OOP way
Swarm models follow a common syntax that helps users to understand the way their parts interact. The
observer swarm and the model swarm are typically designed in a similar way. Methods that will appear
in many classes, for example, include:
Objective C example Java example
+ createBegin; - createEnd; - buildObjects; -
buildActions; - activateIn;
createBegin (); createEnd () buildObjects ();
buildActions (); activateIn ();
There are also methods that allow the input and output of information from the object. By custom, these
33
Chapter 4. The notion of a Swarm
are usually prefaced by the words get and set. For example:
Objective C example Java example
-setParameterValue: (int) value; -(int)
getParameterValue;
Object setParameterValue (int value); int
getParameterValue ();
These methods can be written to so that setParameterValue causes an object to set some internal
parameter equal to a value, and getParameterValue will cause the agent to report back the value.
In addition,there will be methods that carry out the specialized actions dictated by the substance of the
research problem.
The model swarm object is usually subclassed from Swarm and it is the primary object that is
responsible for telling subclasses to build their agents. The model swarm also give those agents a place in
memory, and schedules their activities.
4.3. Managing Memory in Swarms
The allocation and deallocation of memory is a necessary feature in any simulation project. Allocating
and deallocating memory is one of the most troublesome elements of designing software and Swarm is
well equipt to deal with that problem. Swarm provides libraries for this purpose which make the process
transparent to user.
In Swarm, objects are created and dropped using a notion of memory zones, and the "dirty work" of
allocating memory is handled inside the libraries. In the next sections, we discuss the way objects are
created and given a place in memory. When those objects are no longer needed, the program can send
that object the drop message, which removes it from memory.
4.4. What goes on in the buildObjects method?
If the reader inspects just a few of the sample Swarm programs, the importance of the building objects
should become apparent. Objects are named and memory is set aside for them in this stage. In the
buildObjects method, one typically finds commands that not only create the objects being used in
the current class, but there will also be a command which instructs the next-lower level of agent to create
its objects.
Consider the rich example provided by the code from the Arborgames model. In the buildObjects
method of the observer swarm, one finds a large number of commands that create graphical display
objects (objects subclassed from the graph library). One also finds commands that create the simulation
control panel, which will appear on the screen and offer the user the ability to start and stop the
simulation.
34
Chapter 4. The notion of a Swarm
It is vital to note also that the buildObjects method in the observer swarm file triggers the creation
of the next lower level of agents. It creates a memory zone and creates a model swarm in that memory
zone. Using the current style, the code would look like so:
Objective C example Java example
forestModelSwarm = [ForestModelSwarm create:
self]; [forestModelSwarm buildObjects];
forestModelSwarm = ForestModelSwarm
(this.getZone());
forestModelSwarm.buildObjects ();
In the Objective C case only, users may find older versions of this code which accomplish the same
purpose, but are slightly more verbose and do not take into account the fact that the observer swarm
object is itself a memory zone.
modelZone = [Zone create: [self getZone]];
forestModelSwarm = [ForestModelSwarm create: modelZone];
[forestModelSwarm buildObjects];
Note the importance of the last line in either of these excerpts. The first line of the code creates the model
swarm object (in this case, it is called
forestModelSwarm
), but the last line tells that object to create
its own objects by telling the
forestModelSwarm
to execute its own buildObjects method. To
find out what that implies, one must go look in the implementation file (or
.java file in the Java case) for
the
ForestModelSwarm to see what objects it creates.
4.5. What goes on in the buildActions method?
In the standard case, the buildActions method has two important components. It creates objects of
these two classes.
ActionGroup: an ordered set of "simultaneous" events and
Schedule: controls how often the elements in the action group are executed
In the buildActions methods of the Arborgames model, there are plenty of interesting examples. In
the observer swarm, for example, there are commands that schedule the updating of the graphical display
and also there are commands that instruct the lower level classes to execute their own buildActions
methods.
In the
ModelSwarm’s buildActions method, one typically finds the heart of the substantive action of
the simulation. Commands tell agents, or lists of agents, that they should carry out their methods. These
commands are placed into instances of the
ActionGroup class, which means that they will all be repeated
whenever the group is repeated. The repetition is controlled by commands that create schedules and
indicate how often those schedules will be repeated.
35
Chapter 4. The notion of a Swarm
4.6. Merging Schedules in Swarms
As mentioned above, there can be buildActions methods in many different classes. Since each one
can create action groups and schedules, it is important that all of these activities are coordinated in a
logical way. One of the strengths of the Swarm toolkit is that it maintains a coherent, master schedule.
The schedules of each sub Swarm are merged into the schedule of next higher level. Finally all schedules
are merged in the top level Swarm. This synchronization is managed by the Swarm Activity library when
the activateIn:method is called in each successive element of the hierarchy.
This multi-level integration of swarm schedules means that the model can indeed be thought of as a
nested hierarchy of models.
Figure 4-1. Nested hierarchy of Swarms
Swarm
Sub-Swarm
Agent
Schedule
The Interface
The Model
Probes
Sub-sub-Swarm
36
Chapter 4. The notion of a Swarm
A Swarm as a Virtual Computer
Figure 4-2. Swarm virtual computer
At an even more abstract level, the Swarm libraries can be thought of as a layer on top of the operating
system’s kernel. This notion is especially relevant when the user can pause a simulation and individually
interact with agents, reviewing and changing their internal values.
37
Chapter 5. The Graphical User Interface
5.1. Elements of the Swarm GUI
Swarm provides a number of classes and protocols which generate a graphical user interface (GUI) to the
user running a Swarm simulation, including:
Figure 5-1. Line graphs (in this case, a time series)
38
Chapter 5. The Graphical User Interface
Figure 5-2. Histograms
Figure 5-3. Rasters of discrete two-dimensional data
39
Chapter 5. The Graphical User Interface
Figure 5-4. Example
ProbeMaps for the tutorial ModelSwarm and ObserverSwarm
Observer
Swarm
Model
Swarm
A custom ProbeMap
with 4 MessageProbes
A custom ProbeMap
with 1 MessageProbes
ControlPanel is
provided by kernel
All except the last (probes) are fairly self-explanatory and will be dealt with in subsequent chapters. This
section describes how probes appear to the user running a Swarm simulation, and how the user can
manipulate them. Probes also serve purposes other than assisting graphical widgets that the user can
manipulate. However, in this section we will focus only on their role in the context of the GUI of a
running simulation. The construction of the probes using the Swarm libraries is also left to a subsequent
chapter.
5.2. GUI Probe Displays
Graphical probes allow a user to view a snapshot of any object in a Swarm simulation in a graphical
form. There are two distinct kinds of displays the user might see:
DefaultProbeMaps. If an object to be probed is specified without any particular ProbeMap being
specified, then the
ProbeDisplay generated will provide a window of class DefaultProbeDisplay,
which displays all the variables resident in that class structure.
40
Chapter 5. The Graphical User Interface
Figure 5-5. Default ProbeMap (also showing the superclass)
41
Chapter 5. The Graphical User Interface
CustomProbeMaps. If a ProbeMap is specified then the ProbeDisplay follows exactly the specification
as represented by the contents of a
ProbeMap. When used in this manner, ProbeDisplays can generate
tailored interfaces to objects (so for example, we have purposefully hidden certain instance variables in
the
MousetrapModelSwarm class, and have shown only one of the methods which the class understands).
Figure 5-6. Custom ProbeMap
5.3. Using the GUI Probe Display
Common to both the standard ProbeDisplay and the CompleteProbeDisplay:
The different fields in the ProbeDisplay can be updated by typing in new values and pressing Return.
However, certain fields (containing pointers or
ids, for example) cannot be modified and will generate
a beep if such a modification is attempted.
If an instance variable/argument slot is defined to hold an object, then that object can be
drag&dropped into another variable/argument slot by clicking on it with the
first mouse button (a
small rectangle with the name of the object will appear - simply drag it to another object-typed
variable/argument slot and release the mouse button).
Also, if an instance variable/argument slot is defined to hold an object, then that object can be
inspected by clicking the entry for that variable/argument slot with the
third mouse button (a
ProbeDisplay for that object will be generated).
Available Only on the Customized
ProbeDisplay:
42
Chapter 5. The Graphical User Interface
Note that the sunken label at the top of the ProbeDisplay is also active. By clicking on it with the first
mouse button you get a drag&drop’able representation of
self
. By clicking on it with the third
mouse button you get a
CompleteProbeDisplay to
self
.
Available only on the
CompleteProbeDisplay:
The green superclass button can be used to display the succesive superclasses of the object being
probed.
The red hide button can be used to hide classes which are irrelevant thus reducing clutter.
The hide button on the lowest class in the hierarchy has a special meaning since clicking on it
dismisses the entire
ProbeDisplay.
43
Part II. Swarm Applications:
Examples and Illustrations
44
Chapter 6. The Swarm Tutorial: Reprise
Most Swarm users share terminology and perspective that allows them to communicate with each other
about modeling projects. These shared elements are first introduced to most users in the Swarm Tutorial,
a series of exercises prepared by Christopher Langton. The Tutorial exercises are distributed on the SDG
web site in the swarmapps package.
Do Your Homework!
There is no way to get anywhere with Swarm unless you are willing to get your hands dirty. The
Swarmapps package provides some examples of swarm programs that deserve study. That
package also provides the bug tutorial, a series of exercises that all Swarm users must read, edit,
compile, study, test, explore, and investigate.
If you are new to Swarm, and don’t know much about programming in general, and possibly less
about Objective-C in particular, the tutorial series is a perfect place to start. Even if you are an expert
programmer, a study of the tutorial is the right place to start. Many of key terms in Swarm model
buildingare introduced in the tutorial and there is simply no substitute for a careful analysis of the
material.
Java Stops Here!
From hereon in, the Guide will only refer to examples in Objective C. The Guide is in the process of
being updated to include Java examples of the basic Swarm concepts covered in the following
chapters. That said, although many of the concepts described are described in Objective C terms,
most of the concepts carry over intact into the Java context, and (mostly!) only differ in fairly trivial
syntactical ways, so it possible that Java users can benefit from the following sections
6.1. Tutorial Progression
The tutorial gameplan is as follows: Begin with a program written in C that is little more than a basic
"hello world" program about a "bug" creature that wanders. Through a series of steps which first
introduce Objective-C and then the Swarm hierarchical modeling approach, one can gain a good
grounding in Swarm modeling.
The tutorial outline is as follows:
1. simpleCBug. Simple C code about a bug
45
Chapter 6. The Swarm Tutorial: Reprise
2. simpleObjCBug. Bug is now Objective-C class
3. simpleObjCBug2. Adds FoodSpace object
4. simpleSwarmBug. Introduces the
ModelSwarm as the central organizing element. From the class
Swarm in the Swarm library, this code creates subclass ModelSwarm, and the instance of ModelSwarm is
created and called
modelSwarm
(in main.m). In the class ModelSwarm, one finds an implementation
of the
Schedule class, the workhorse that keeps the Swarm train moving on time.
5. simpleSwarmBug2. Introduces the
bugList
, an instance of the List class, and illustrates some
ways in which simulations with many agents can be organized.
6. simpleSwarmBug3. Introduces the Swarm class
ObjectLoader that the can grab data from a file and
read it into an object (in this case, the
modelSwarm
).
7. simpleObserverBug. Subclasses from the Swarm class
SwarmGUI to create a new class
ObserverSwarm, an instance of which is created and called
observerSwarm
. This is the first
example with a complete Swarm hierarchy which begins with main.m and translates actions from
ObserverSwarm to ModelSwarm to individual agents.
8. simpleObserverBug2. This example adds probes that allow users to click on graphics to reveal
information inside them.
9. simpleExperBug. Introduces the possibility that a simulation might be run over and over in "batch"
mode while the graphical interface reports summaries of the runs to the user.
6.2. What Are You Supposed to Learn from the
Tutorial?
So, after you worked on the tutorial for 20 hours or so, what then? You should know all kinds of details
about how Swarm can be used, of course, but there are some bigger themes.
It is not vital to know how to model bugs (although, perhaps for an entomologist...), rather, it is vital to
understand that Swarm is a toolkit that provides a housing for a modeling exercise. Swarm imposes no
inherent limitations on the nature of agents that can be represented within its framework.
Don’t read much further in this user guide until you work on the tutorial. You will know if you have
worked on it long enough when you understand clearly each of the following points.
Swarm has many classes to make the modeling job easier. There are workhorse classes like Swarm,
SwarmGUI, and SwarmObject, but also there are many "little helpers" like List. Getting to know the
46
Chapter 6. The Swarm Tutorial: Reprise
ins-and-outs of these little helpers is extremely important.
Swarm handles memory details. Did you note that there are no malloc and free and other standard
C memory-managing commands in Swarm code? Those commands exist, but they exist inside the
Swarm library, and they are accessed on behalf of users who use create or createBegin and
drop to access memory for objects and get rid of them. To create objects (instances of classes) in
Swarm, there must either be a createmessage sent to a class or there must be a
createBegin/createEnd pair that serves as bookends for commands that create an instance, set
its internal state, and complete the instantiation.
Case is important. Including the right header files may give you access to "factory objects" like List
or Schedule. You can use any name you like for the objects that are created as instances. By custom, an
instance of a class–an object–is named in small letters, such as
bugList
as an instance of List or
modelSchedule
as an instance of Schedule. In the tutorial, when there is a single instance of a class
to be created, by convention, it is typically named the lowercase version of the class name, such as the
foodSpace
object which is an instantiation of FoodSpace.
Neatness counts. As in any kind of programming task, neatness counts. Classes in Swarm are created
with methods that group together their jobs by functions. One will often find, in
ObserverSwarm for
example, commands that create a
modelSwarm
instance and then issue it these commands:
[modelSwarm buildObjects];
[modelSwarm buildActions];
The buildObjects method creates objects and buildActions creates schedules. If one wanted to,
one could build a gigantic method in the
ModelSwarm class called doStuff and then call that method
with:
[modelSwarm doStuff];
Programs written with this approach are hard to proofread and manage. It is much better to write small
methods, each of which accomplishes a relatively specific task.
There is often a need for "record keeping" classes. In order for data to be displayed meaningfully
in a graph, for example, it must be provided to the graph object in a format that the graph object can
handle. The class
World in simpleObserverBug is subclassed from Swarm’s Grid2d class.
Graphics are optional, but nice. Commands in the Observer Swarm control the graphical display.
There are many kinds of graphs and ways to alter their appearance. It is not necessary to design a
Swarm program to make pretty pictures, however. One might just as well run in a "batch" mode that
prints numbers into files for later inspection. There is a useful example of the batch mode in the
Heatbugs code.
Open Source means open the source. To find out what messages an instance of a class will respond
to, you should first consult the API
1
: the Swarm Reference Guide. In most cases the average user will
1. Application Programmers Interface
47
Chapter 6. The Swarm Tutorial: Reprise
encounter, consulting the API is sufficient, but when you really need to know how something is
implemented (either to understand the efficiency implications of using a certain method in your
program or if a particular method appears to not behave as documented), you can go look in the
Swarm source code itself. That’s what the members of the Swarm team do when users ask questions.
6.3. After the Tutorial: What now?
After the tutorial exercises are finished, one can then proceed to study the example applications in
swarmapps and others that are available (for free!) on the web. The application called Heatbugs in
the swarmapps package gives a rich and workable example of a simulation that builds on the ideas in
the tutorial.
48
Chapter 7. Creating Objects In Swarm
The way in which objects are created depends on a computer’s compiler and the software libraries
available to the user. The implementation of Objective C on a system using the GNU compiler will not
be exactly the same as the implementation on a Next system. While most of the points made in the
literature on Objective C easily carry over to Swarm modeling, the commands needed to create objects
are an exception. In the Objective C manual for Next systems, for example, one finds a syntax methods
init and alloc that are not used in Swarm. That’s why a brief study of object creation is important.
7.1. Begin at the Beginning
Pick any Swarm application you like, such as Heatbugs. Look in main.m. What do you find? There’s a
check to see if the GUI mode or batch mode is to be run, and depending on that choice, either the
ObserverSwarm or the BatchSwarm is designated as
theTopLevelSwarm
.
Suppose we have do not do anything special when compiling and running the heatbugs executable, so
the GUI mode is used. In that case, the relevant code in
main.m is this:
if (swarmGUIMode == 1)
{
theTopLevelSwarm = [HeatbugObserverSwarm createBegin: globalZone];
SET_WINDOW_GEOMETRY_RECORD_NAME (theTopLevelSwarm);
theTopLevelSwarm = [theTopLevelSwarm createEnd];
}
The first command inside the brackets tells the class HeatbugObserverSwarm to execute its
createBegin method and return an object which is to be named
theTopLevelSwarm
. In this
example, the
HeatbugObserverSwarm is the class and also serves as a "factory object", an object that can
build instances of its class. The second command is a macro that saves window positions on subsequent
runs of the program. It is set between the createBegin and createEnd methods because it is
setting permanent features of the object
theTopLevelSwarm
. The last command "seals" off the
creation phase by telling the recently created object
theTopLevelSwarm to run its createEnd method.
In the Swarm Reference guide, many of the protocols have methods that are divided between three
phases. The phases are "Creating", "Setting", and "Using". It is important to pay attention to the phase in
which a method is listed. Methods or macros listed in the Creating phase must only be used between the
createBegin and createEnd messages. If such a method is used after the createEnd, it will cause
the program to fail. Similarly, a method in the Using phase must be used only after the createEnd method
has finished. Methods in the Setting phase can be used at any time in an object’s life cycle.
49
Chapter 7. Creating Objects In Swarm
7.2. Detailed Look at createBegin/createEnd
Now take the next step and look at the createBegin and createEnd methods that are called by the
code in
main.m. Follow the steps into HeatbugObserverSwarm.m. Here you find the methods
+createBegin and -createEnd. The plus sign on createBegin indicates that this method
cannot be executed by an instance of the class
HeatbugModelSwarm, but rather only by the factory object.
Here is a portion of the method createBegin:
+ createBegin: aZone
{
HeatbugObserverSwarm *obj;
id
ProbeMap probeMap;
obj = [super createBegin: aZone];
obj->displayFrequency = 1;
// [Code that creates "probemaps" omitted here]
return obj;
}
This a good example of how the Swarm toolkit handles the creation of objects. The pointer to the class
HeatbugObserverSwarm named obj is defined. Since HeatbugObserverSwarm is subclassed from GUISwarm,
it is important to be sure that all of the important variables of a
GUISwarm object are initialized and
inherited by
HeatbugObserverSwarm. This is done in one step by telling the superclass to execute its
createBegin method. Since the classes are linked together in a hierarchy, each higher level class in
turn executes its createBegin statement. That is how the instance of the class ends up setting values
for all the variables that it inherits.
The createBegin method of its superclass is called to put the created objects in
aZone, which is the
name of the space passed in from
main.m. The memory zone that is created is returned and set equal to
obj
. Then the return obj command gives back the created object to the calling code, in this case
main.m, which then treats it as
theTopLevelSwarm
.
The reader can investigate in the Swarm source code to see that
GUISwarm inherits through a hierarchical
chain the ability to create memory zones and objects.
GUISwarm is subclassed from Swarm, which in turn
inherits from
CSwarmProcess. That class is defined in the activity directory of the source code in a file
called
SwarmProcess.m. This is the first place where you will find createBegin and createEnd
methods as you move up the inheritance tree, so it must be that these are the methods that are executed
when
super
is told to do something in this code.
The createEnd method in
HeatbugObserverSwarm.m is quite simple:
- createEnd
{
return [super createEnd];
}
50
Chapter 7. Creating Objects In Swarm
In a case like this, when the super class is inside the Swarm library, it may be hard to figure out exactly
why this command is needed. As a matter of fact, it is not necessary in this case at all, but it does not do
any harm. If it were omitted from this class, then this class would just inherit createEnd method from
the somewhere above in the family tree. By using it in this way, we make sure that the commands of the
super class’s createEnd method are executed, and this may be important because those steps might
initialize some variables that this class inherits.
There are cases in which the createEnd statement may be more substantial. In the createBegin
phase, we typically find commands that set permanent features of objects. Some methods that initialize
instance variables can also be included. In the example above, the variable
display frequency
inside *
obj
is set equal to 1. These variables are set at the first possible opportunity because other
variables may depend on them. After
main.m calls the createBegin method, main.m may include
statements that further tailor the state of the object and those commands may depend on values set in
createBegin. Finally, when
main.m calls createEnd, a new slew of commands may be executed
that define further elements of the object.
The createEnd statement may be a convenient place to put any code that completes the initialization
of an object. For example, suppose inside there is a variable called
age.IncreateEnd, one might find
this:
- createEnd
{
[super createEnd];
age=0;
return self;
}
The super class’s createEnd method is executed, which will assure that any variables initialized there
are set properly. Then the instance variable age is set equal to 0. (Sometimes you will find examples in
which createEnd is a "garbage can" that collects a large number of commands that set initial values
for variables inside the object. These commands might as well be regroupedand put into a new method
inside the object that might be called
setInitialValues that would be executed after the createEnd.
The readability of the code is enhanced that way.)
The create message causes the receiver to carry out both its createBegin and createEnd
methods. Why didn’t we always use create? Well, sometimes we need to define variables between the
createBegin and createEnd steps, as seen in
main.m. If there is no need to set values in that way
(no methods are listed in the Creating phase in the Swarm Reference Guide are used), then create is
enough.
7.3. Swarm Zones and Recursive Objects Creation
51
Chapter 7. Creating Objects In Swarm
One of the most troublesome exercises in computer programming is the management of dynamically
allocated memory. The correct usage of dynamic memory requires a great deal of care, and when a
portion of memory is no longer needed, is must be "freed," made available to the central processor. If
memory is allocated and then forgotten, a "memory leak" is said to exist because the program does not
tell the operating system to reclaim unused memory addresses.
The Swarm libraries are designed to handle memory allocation with a minimum of user intervention. The
createBegin and create commands allocate memory and the user is not expected to think about where
the RAM comes from to store an object. Similarly, when a program is finished with an object, that object
can be sent the drop message and that should take care of freeing the memory that the object used.
The create statements used in Swarm typically have this flavor:
someUserCreatedObject = [SomeSwarmLibraryObject create: someMemoryZoneHere];
(The method create can be replaced by a createBegin/createEnd pair as described above.)
More specific examples are discussed below and are of course scattered throughout the Swarm examples.
The important thing is that an object in the Swarm library is able to respond to a method that creates an
instance of itself and that instance lives in a memory zone that is managed by the Swarm library.
In the
main.m file, the top level Swarm is created and it is allocated into an instance of Zone called
globalZone
.
theTopLevelSwarm = [HeatbugObserverSwarm createBegin: globalZone];
This
globalZone
is created when the initSwarm function is called at the beginning of a swarm
program. The top level Swarm is told to create itself in that space. Any Swarm objects of type
Swarm or
GUISwarm are able to serve as memory zones. Inside the ModelSwarm one sees a command such as:
probeMap = [EmptyProbeMap createBegin: self];
This tells the EmptyProbeMap class in the Swarm library to create an instance of itself in the memory zone
allocated by the
ModelSwarm, and that allocated object is to be named
probeMap.
The objects at the top level of the swarm hierarchy (whether Swarm or GUISwarm) have the power to
"create space" for objects that live inside them. As the code in
main.m proceeds through the creation of
theTopLevelSwarm
, it is allocating memory and setting other important creation-state variables.
Then, that newly created object is told to go through its paces:
[theTopLevelSwarm buildObjects];
[theTopLevelSwarm buildActions];
[theTopLevelSwarm activateIn: nil];
[theTopLevelSwarm go];
When you go look at the buildObjects method executed by the
theTopLevelSwarm
, what do
you find? Depending on what edition of the Heatbugs source you have, you will find something like this:
52
Chapter 7. Creating Objects In Swarm
heatbugModelSwarm = [HeatbugModelSwarm create: self];
In this code, the
self
is the observer level, meaning that the HeatbugModelSwarm class is told to create an
instance of itself in the memory zone provided by the observer, and that allocated object is named
heatbugModelSwarm
.
If you then follow the code into the
HeatbugModelSwarm.m file, you find it has createBegin commands
that initialize a number of instance variables and objects. Unless you have a pretty old piece of code,
those objects will be created in the memory zone
self
, the space provided by the model swarm itself.
Objects that are of type
SwarmObject are not memory zones, and so when objects are created inside
classes that inherit from
SwarmObject, a command to allocate memory must be used.
bugPixmap = [Pixmap createBegin: [self getZone]];
The
bugPixmap
object is created inside Heatbug.m, but the name of the memory zone where that object
"lives" has to be retrieved with the
[self getZone] command. The [self getZone] method returns the
name of the zone in which the bug exists, which in this case is heatbugModelSwarm.
7.4. Using Swarm Library Objects and Header Files
It often seems as if objects appear by "magic." It is more reasonable to say they are provided by the
Swarm library in a way that is not entirely obvious. For example, suppose you want to create a list of
objects. One can declare an object
listOfFriends
and then create it, like so:
id listOfFriends;
listOfFriends = [List create: self];
You see little bits like this all over example code from Swarm projects. Where does this List class object
come from? Why are you able to use it even though there is no import statement for List.h at the top of
the program? It seems as though, if you want to make a call on the List class, you ought to include
List.h at the top of your file, right?
To use many of the Swarm classes, it is not necessary to use such an explicit import statement since you
are not subclassing. Instead, it is necessary to include one of the "general purpose" header files that
corresponds to the major sections of the Swarm library. To create List instances, for example, one needs
to import the "general purpose" collections.h, which declares not only List, but other collections classes
as well.
The general purpose header files can be found in the include directory of your swarm installation. They
are:
activity.h
53
Chapter 7. Creating Objects In Swarm
analysis.h
collections.h
collections.h
gui.h
objectbase.h
random.h
simtools.h
simtoolsgui.h
space.h
As you browse the Swarm Reference Guide, you will find many protocols that adopt the CREATABLE
protcol, which means that you can use them to create objects in your code. When you use them, import
one of these library headers. For example, to create List objects, import
collections.h. That header file
should be included in any file that refers to a List, Map, Set, or any of the other creatable collections
objects.
Should the general purpose header file be included in the .h (header) file or the .m (implementation) file
of your class? Generally speaking, it is only necessary in the .m file, since that is where you are doing the
work of creating the object. The only exception to this rule arises if you refer to the protocol protocol in
your header file. It is necessary to include the collections.h in your header file if you want to declare an
object that will adopt a protocol, as in
id List aList;
If you forget to import collections.h, the compiler will fail and say there was a parse error. This happens
because it does not have a class or protocol List in its purview, and so it assumes you have made a
typographical error.
On the other hand, if your header file uses a general declaration, as in
id aList;
then there is no need to include collections.h in the header file. It should only be included in the
implementation file for your class.
Explicit importing of a class-specific header file is only required when you need to subclass from that
file. Since your header file declares that you are creating a class, and it defines the superclass, then the
import statement must be included in your header file. SwarmObject is the most frequently used
superclass, so consider it for example. Your class’s header file should import both the general purpose
library header objectbase.h as well as
objectbase/SwarmObject.h
We will summarize this by offering two rules of thumb:
54
Chapter 7. Creating Objects In Swarm
if you use a class that conforms to a protocol (such as List) to create objects in your own program,
you need to include one of the general Swarm library headers.
if, however, you are subclassing from a class that adheres to a protocol, you need to import the header
file for that class.
We hasten to point out that not all of the Swarm protocols will allow you to subclass from them. To avoid
some serious complications, the List type cannot be used to create user-specific classes. One can create
Lists and use them as intended, but one cannot create variants of the Swarm List class to customize their
behavior for a specific project.
As good coding practice, you should try to keep your files clean. Each file should only include imports
for header files that you actually reference in that particular interface/implementation file pair. Don’t
adopt a "include everything" mentality when importing files.
7.5. Variations on a Theme
Once you have seen how an object can be created, you should start thinking about how your simulation
will be organized. Within the standard Swarm approach, you begin with
main.m allocating space for the
top level swarm, which may be either a gui or batch swarm. Then the model swarm object is created in
that top level, and the model swarm in turn creates the substantively important objects that embody the
model you seek to investigate.
There are a number of different ways in which the creation of objects can be managed. Some are more
intuitive than others, some are more "reusable" than others. Since the first Swarm exercise for most
people involves bugs, it is not surprising that many examples of Swarm code follow the convention of the
bugs project. As found in SimpleSwarmBug3, for example, the
ModelSwarm.m file creates the bug objects
in this way:
- buildObjects
{
Bug *aBug;
int x, y;
[some lines omitted here]
bugList = [List create: self];
for (y = 0; y < worldYSize; y++)
for (x = 0; x < worldXSize; x++)
if ([uniformDblRand getDoubleWithMin: 0.0 withMax: 1.0] < bugDensity)
{
aBug = [Bug createBegin: self];
[aBug setWorld: world Food: food];
aBug = [aBug createEnd];
[aBug setX: x Y: y];
[bugList addLast: aBug];
}
55
Chapter 7. Creating Objects In Swarm
reportBug = [bugList removeFirst];
[bugList addFirst: reportBug];
return self;
}
This code cycles over the spaces in a lattice, and if the conditions are right, it causes the Bug class to
create an instance of itself, called
aBug
, and then that instance is added to the
bugList
.
Some changes can be made to make this code a little more versatile. For example, create a new method
called spawnOneBug that moves out the bug creation steps.
- buildObjects
{
Bug *aBug;
int x, y;
[some lines omitted here]
bugList = [List create: self];
for (y = 0; y < worldYSize; y++)
for (x = 0; x < worldXSize; x++)
if ([uniformDblRand getDoubleWithMin: 0.0 withMax: 1.0] < bugDensity)
{
[self spawnOneBug];
}
reportBug = [bugList removeFirst];
[bugList addFirst: reportBug];
return self;
}
- spawnOneBug
{
aBug = [Bug createBegin: self];
[aBug setWorld: world Food: food];
aBug = [aBug createEnd];
[aBug setX: x Y: y];
[bugList addLast: aBug];
return self;
}
Why is this more versatile? By isolating the steps necessary to create a bug and add it to the
bugList
in
the spawnOneBug method, we make it much easier to add new bugs to the simulation as time goes by.
7.6. How Do You Kill Off Those Poor Little Devils?
56
Chapter 7. Creating Objects In Swarm
If you look at Swarm examples for any amount of time, you can’t help but run into objects that get
dropped. Little "helper objects" like indexes for lists are created and just as readily discarded with the
command:
[someIndexName drop];
If everything goes the way it is supposed to, this should take the object out of memory and free that
memory for the program to reuse.
What if the objects inside your simulation are supposed to be born and killed through time? The Swarm
bug tutorial mainly focuses on models in which a population of actors is created at the outset and those
individuals remain in existence throughoutthe length of the program. What if we wanted code to model a
world in which the happy HeatBugs could reproduce themselves, or what if the unhappy ones could die
and be freed from their never ending search for a place neither too cool or too hot?
The Swarm SugarScape model provides an excellent example of a way to manage the birth and death
of agents in an on-going model. The sss model’s
ModelSwarm.m file contains the critical ingredients. It
has a method addNewRandomAgent which does what spawnOneBug does–it includes all the
commands that create an instance of a
SwarmObject and initializes it. sss also provides a handy structure
to kill off agents and replace them with new ones. This is managed in a three stage process. The model
swarm creates a Swarm list object called
reaperQueue
. When an event occurs that forces an object
below the survival threshold, then that object is added to the
reaperQueue
by the agentDeath
method. Then the model Swarm’s schedule includes a command that removes the dead agents from the
reaperQueue
. The reapAgents method transverses the list of agents who are to die, it removes
them from the list of active agents and then tells them to drop themselves from memory.
- agentDeath: (SugarAgent *)agent
{
[reaperQueue addLast: agent];
if (replacement) // Replacement rule R (p.32)
[self addNewRandomAgent];
return self;
}
// remove all the agents on the reaperQueue from the agentList
// This allows us to defer the death of an agent until it’s safe to
// remove it from the list.
- reapAgents
{
id index, agent;
index = [reaperQueue begin: [self getZone]] ;
while ((agent = [index next])) {
[agentList remove: agent];
[agent drop];
}
[reaperQueue removeAll];
[index drop];
57
Chapter 7. Creating Objects In Swarm
return self;
}
58
Chapter 8. Doing the Chores: set and get
Object-oriented programming organizes the way programmers think about information in a new way.
The objects maintain their variables (the "instance variables", or IVARs for short) and the information
contained in those variables is private, self-contained within the object. This has benefits in the design of
code and it also captures some intuitions the autonomy of individual agents in a simulation exercise.
Objects are thus insulated, more or less, and although this makes some things easier to code, it also
makes some things more difficult. For example, in C a variable can be set and its value can be changed
anywhere in the program. In object-oriented languages like Objective-C, an object can hold several
variables and those values can only be changed by the object itself if we remain within the recommended
limits of good programming habits. Some ways to go outside those bounds will be discussed below, but
generally speaking it is a good idea to respect the fact that objects maintain their own data.
If objects are maintaining their own data, how do we manage information in a Swarm project. Early on in
the development of Swarm, the coders adopted a convention (common to Objective C, Java, Smalltalk
and numerous other object-oriented languages) that the term set starts a method name that sets a value
inside an object, such as setIdealTemperature or setAge. The term get is used as the beginning
of a method that causes the agent to return some value, such as getIdealTemperature or getAge.
8.1. Get and Set Methods
Get and set methods are needed to pass information among objects. For example, consider Heatbugs.
In the
Heatbug.m code, one finds a methods that set information inside the bug and also methods that
retrieve information from it. Consider the method setIdealTemperature
- setIdealTemperature: (HeatValue)i
{
idealTemperature = i;
return self;
}
The Heatbug object has an instance variable called
idealTemperature
, and this sets the value of that
variable.
If some other object needs to know the heatbug’s ideal temperature, what has to be done? We would have
to add a method to the
Heatbug.m that returns the value of
idealTemperature
. Something like this
might suffice:
- (double) getIdealTemperature
{
return idealTemperature;
}
59
Chapter 8. Doing the Chores:
set
and
get
As much as possible, it is recommended that information be exchanged in this way. Hence, when the
observer swarm needs a list of all the agents in a simulation in order to create a graph, the model swarm
should have a method, such as getAgentList, that returns a list of agents that the observer swarm can
use.
8.2. Using Set Methods During Object Creation
Consider the way the model swarm level of a simulation can be designed. If the values of many variables
are set inside the
ModelSwarm.m file, and those values are to be passed to the individual agents at the time
of creation, then the code that creates individual objects might be designed like this:
aBug = [Bug createBegin: globalZone];
aBug = [aBug createEnd];
[aBug setWorldSizeX: xsize Y: ysize];
[aBug setFoodSpace: foodSpace];
[aBug setX: xPos Y: yPos];
[aBug setIdealTemp: [uniformDblRand getDoubleSample]];
This code presupposes that the ModelSwarm.m file has pre-existing variables (probably integers)
xsize
,
size
,
xPos
, and
yPos
, as well as an object
foodSpace
and an object
uniformDblRand
that can
give back a random number. This code also presupposes that set methods exist for the
Bug class that can
get these jobs done.
There are some matters of "taste" and "judgment" that affect model design. One might ask, for example:
“why does this code set the ideal temperature in this way?” Why not create a method inside the
Bug.m
file, such as initializeValues like so:
- initializeValues
{
idealTemperature= [uniformDblRand getDoubleSample]
return self;
}
If this method existed, then the code that creates the bug and sets values in it could have the command
[aBug setIdealTemp: [uniformDblRand getDoubleSample]];
replaced with this:
[aBug initializeValues];
This would achieve the purpose of setting the
idealTemperature
variable inside the object called
aBug
. And, from the information-hidingperspective of object-oriented programming, it seems better
because the value drawn for the variable
idealTemperature
is never exposed to any other object.
60
Chapter 8. Doing the Chores:
set
and
get
There are a few practical reasons why the first way of setting the ideal temperature might be preferred.
First, for the programmer’s convenience, it is nice to have as many of the "parametric" changes in a
single file as possible. The Bug class can be written and never edited again if all of the changes needed
are kept in the
ModelSwarm.m file. Second, you might save memory dealing with these things in the
ModelSwarm.m file. Suppose that the object
uniformDblRand
has to be created in order to draw a
random number. If you insist on writing a method like initializeValues inside the
Bug.m, then you
need to worry about how that random number generator object is created inside each bug object. It
certainly saves memory to create just one random generator in the
ModelSwarm.m file and then draw
numbers from it inside the model swarm itself. There are some good arguments for this approach in the
literature on random number generation. The issue seems somewhat esoteric, but the argument is that
one is better off making repeated draws from the same random number generator than making one call
against each of the many random number generators. For reasons like this, Swarm examples tend to have
information translated into objects from the model swarm level, even though it is technically allowable to
have that information-creation process completely isolated within the object.
8.3. Passing Information Around
In order to send messages to objects from another class, it is necessary not only to use the correct
message, but also to import that class’s header file into the code. The
ObserverSwarm.m file can only tell
the
HeatbugModelSwarm to run its createBegin method if ObserverSwarm.m includes the header file for
the
HeatbugModelSwarm.InHeatbugObserverSwarm.m, we find this:
#import "HeatbugModelSwarm.h"
The inclusion in the "m" file is sufficient if no reference to the HeatbugModelSwarm is necessary in the
HeatbugObserverSwarm.h file. It may be necessary to move the import statement into the header file (the
"h" file), however, if any references to a class are contained in the "h" file. In
HeatbugModelSwarm.h, for
example, one finds these import statements:
#import "Heatbug.h"
#import "HeatSpace.h"
Since these are included, the variable and method definitions can refer to elements of these classes. The
variable list declares a pointer to an object of type
HeatSpace:
HeatSpace *heat
and there is a method that has an object of type Heatbug as an argument:
-addHeatbug: (Heatbug *)bug;
61
Chapter 8. Doing the Chores:
set
and
get
Many Swarm programmers have run into the following problem. As we have seen, It is not difficult to
have the model swarm level create an object. Through the set methods, various values can be set inside
the object by commands in the model swarm. However, the programmer wants the agent to be able to
access variables inside the model swarm as the simulation progresses. Suppose the
HeatbugModelSwarm
has an instance variable called
numberOfBugsAlive
, and inside HeatbugModelSwarm we define a
method getNumberOfBugsAlive that returns that number. Suppose further we want any heatbug to
be able to find out how many bugs are alive at any instant. It is tempting to write inside
Heatbugs.m
something like:
[heatbugModelSwarm getNumberOfBugsAlive];
to access that information. That construction will not work, however, unless we take some special
precautions. First, each
Heatbug has to be made "aware" of what model swarm it belongs to. Inside
Heatbug.h, a variable would have to be defined:
id heatbugModelSwarm;
To set the value of this variable, the Heatbug.m file needs to have a method like this:
- setModelSwarm: (id) nameOfSwarm
{
heatbugModelSwarm = nameOfSwarm;
return self;
}
The value of the instance variable
heatbugModelSwarm
has to be set in the model swarm when other
values are set. When the
HeatbugModelSwarm is creating bugs, it sets the other values like the ideal
temperature and the position, but further it would set itself as the model swarm to which that bug
belongs, like so:
aBug = [Bug createBegin: globalZone];
aBug = [aBug createEnd];
[aBug setWorldSizeX: xsize Y: ysize];
[aBug setFoodSpace: foodSpace];
[aBug setX: xPos Y: yPos];
[aBug setIdealTemp: [uniformDblRand getDoubleSample]];
[aBug setModelSwarm: self];
This assures that, inside aBug, the value of the instance variable
heatbugModelSwarm
is defined.
The final precaution is that the header file
HeatbugModelSwarm.h must be imported into Heatbug.m.Itis
very important that the import statement is added to
Heatbug.m, not Heatbug.h. If it is added to
Heatbug.h, then the program will not compile because the inclusion causes a circularity: Heatbug.h is
included in
HeatbugModelSwarm.h,butHeatbugModelSwarm.h is also included in Heatbug.h. Putting the
import statement in the "m" file avoids that ciruclarity. And, since the import has to be in the "m" file, the
62
Chapter 8. Doing the Chores:
set
and
get
definition of the variable
heatbugModelSwarm
in Heatbug.h uses the generic type id, rather than a
specific type, such as
HeatbugModelSwarm.
Many swarm examples are designed to avoid the need to allow objects created by model swarm to also
access information directly from it. This is usually done by creating a "space" object that keeps records
on the model swarm. Individual agents report their positions to the space and the space calculates any
necessary statistics about the swarm. The code for the space object can include get methods that the
individual agents can execute when they need information about their environment. This approach has
the added advantage that additional methods can be inherited from the general space objects in the
Swarm library.
8.4. Circumventing the Object-Oriented Guidelines
If one wants to avoid treating objects as containers that hold both data and methods, one can do so. The
C language allows the creation of global variables, ones that can be accessed in any part of the code.
These
external variables exist outside a particular class and are thus available to it. The names used for
external variables must be unique. One cannot have a global variable called
temperature
as well as a
temperature variable defined as an instance variable for each object. There are some occasions in which a
program can be made to run more quickly if the whole get/set exercise is circumvented by creating a
global variable.
Another way in which the object-oriented guidelines can be circumvented is the use of the
-> operator.
Suppose we have an object called
dog
and it has instance variables
numberOfBones
and
timeSpentSleeping
. Ordinarily, within the object-oriented paradigm, the
numberOfBones
would have to be set by a method such as
setNumberOfBones
. However, the language does allow a
shortcut of the following sort. The syntax
dog->numberOfBones refers to the value of the instance variable
numberOfBones
inside the object named
dog
. Hence, one could have a statement:
dog->numberOfBones = 3;
that sets the
numberOfBones
to 3 inside the dog. This kind of code is considered to be heavy-handed
and brutish because it does not use the methods written for the dog class with which it can set that value
and update it. A mistake made with the
-> operator can corrupt the values inside an object.
Even though the usage of
-> is discouraged, one does find examples of this syntax in Swarm code.
Almost all Swarm examples use this kind of shortcut in the createBegin phase of the model swarm
file, for example. This is done, however, because there is no alternative. We want the GUI probe display
to allow the user to adjust parameter values before the simulation commences. It is thus necessary to set
values inside some objects even before those objects have finished their createBegin/createEnd routine.
63
Chapter 9. Building Schedules
The core of the Swarm system is the set of features that enhance the design process of simulation
projects. The scheduling apparatus is one of the truly important elements of the Swarm system because it
offers a way to integrate the actions (and responses) many different agents in many different levels of a
simulation.
The actions that go on in a simulation are orchestrated by a objects that respond to the
Schedule protocol.
Schedules are generally built in the buildActions method of an object. A Schedule is something like
a calendar in which one might put a red letter X when an important event is supposed to occur. The user
then defines what the important events are and integrates them into the
Schedule. Then the Schedule must
be activated within the larger Swarm hierarchy of the object.
9.1. Building Schedules
Here is an example of some code that makes a simple Schedule. This sort of Schedule might appear in
the
ModelSwarm
level of the bug tutorial, for example.
- buildActions
{
modelSchedule=[Schedule createBegin: self];
[modelSchedule setRepeatInterval: 1];
modelSchedule = [modelSchedule createEnd];
[modelSchedule at: 0 createActionTo: aBug message: M(step)];
return self;
}
The first three lines in the method create the Schedule named
modelSchedule
. It might as well be
aBugsLife
or any other name the user chooses. Between the createBegin and createEnd
methods, the only detail that this
Schedule sets is the repeat interval, which is one. That means that all of
the actions assigned to the
modelSchedule
will be executed at each time step.
Once the code has created a
Schedule object and set the repeat interval, then that object can be told to
insert actions into its
Schedule. These actions cause the
modelSchedule
to build commands that
make the desired actions happen. No two simultions are exactly the same, of course, and so there are no
hard-and-fast rules. Generally, however, the
modelSchedule
is usually told to do either of two
methods, at:createActionTo:messageor at:createActionForEach:message.The
first is used when the action of a single object must be
Scheduled, while the second is used to Schedule
activities for whole lists.
In this simple example, the
modelSchedule
has only a single action, which instructs the one bug in
the simulation, whose name is
aBug
, to carry out its method called step. It might be that there is a
64
Chapter 9. Building Schedules
whole list of bugs,
bugList
, and each bug has to be instructed to carry out its step action. In such a
case, the command would be:
[modelSchedule at: 0 createActionForEach: bugList message: M(step)];
Some additional scheduling topics are discussed, but first the abstract question of selectors and the M
operator must be addressed.
9.2. What’s that M() Thing?
The commands that tell a Schedule to add actions usually have notation like like
M(someMethodName) at the end. M() is a macro used in Swarm to mean that the selector for the
message "step" is returned. Selector, or
SEL, is a variable type in Objective C which refers to the abstract
name used in the compiler to refer to a method, in this case step. M is short for message (or method)
and was "created to save the time of typing @selector(myMethod)," in the words of Nelson Minar.
Many of the methods available in the Swarm library want input in the form of a selector, an symbolic
reference to a method name, and the M() notation is one shorthand way of giving it what it wants.
Some of the methods in the Swarm library will also want a list of parameters that go with the selector.
Suppose, for example, you have a psychologist agent that has this method:
- dealWithProblemBetween:anObject And: (id) anotherObject;
Presumably, you have some code in which there are objects, perhaps named
bill
and
susan
, and
when you are not needing the Swarm libraries for anything, you just tell your psychologist agent to carry
out that method with a command such as:
[yourShrinksName dealWithProblemBetween: bill And: susan];
The name of this method is dealWithProblemBetween:And: and its input variables are two
objects.
Now suppose you have a whole list of psychologists, and that you want each one of them to deal with the
problem between bill and susan. Furthermore, you want them to do it over and over again. To do that,
you need Swarm to schedule the job, so you run into that selector problem again. Notice in the Swarm
documentation that the
Schedule protocol can respond to a method called createActionForEach,
which has a prototype like this:
- at: (timeval_t)tVal createActionForEach: target message: (SEL)aSel : arg1 : arg2
At the end of this definition, we see this method wants to be given a selector, and then the two arguments
that go with it. We know we can grab the selector of the command we want with
65
Chapter 9. Building Schedules
M(dealWithProblemBetween:And:),so when we tell the schedule object to make each
psychologist look into the
bill
and
susan
problem, we need a command like this:
[modelSchedule at: 0 createActionForEach: listOfShrinks mes-
sage: M(dealWithProblemBetween:And:):bill:susan];
Admittedly, this notation seems ungainly, but it works.
It is a difficult understand the reason why the selector is needed in the first place. If one is not well versed
in Objective C, it may be best just to follow the form of the examples provided with Swarm and not
worry about the M() until it is absolutely necessary.
1
You can go look in the Swarm libraries to see many examples to show why selectors are so vital. Just by
coincidence, we happened to be looking at the
Object2dDisplay.m file, where there is a particularly clear
example of how these selectors come into play. The
Object2dDisplay’s display method is often
scheduled in the observer swarm level of projects that draw on
ZoomRaster grids. In order to make this
possible, the selector is required.
When an instance of
Object2dDisplay is created, one of the first thing the user does it tell that object
what the display message for its members is. The
Object2dDisplay is passed a selector by the
"setDisplayMessage" method.. This bit of code is from SwarmSugarScape’s
ObserverSwarm.m file.
agentDisplay = [Object2dDisplay createBegin: [self getZone]];
[agentDisplay setDisplayWidget: worldRaster];
[agentDisplay setDiscrete2dToDisplay: [sugarSpace getAgentGrid]];
[agentDisplay setObjectCollection: [modelSwarm getAgentList]];
[agentDisplay setDisplayMes-
sage: M(drawSelfOn:)]; // note the draw method passed as selector
agentDisplay = [agentDisplay createEnd];
The Object2dDisplay is told which widget it is addressed to setDisplayWidget and which agent list
(
[modelSwarm getAgentList]
). Note how the object
agentDisplay
is told to set inside it the
value of the selector M(drawSelfOn:). It does not ask for the additional information of the input
variables that would ordinarly follow drawSelfOn:. It only wants the selector.
1. On the off chance that you have reached a point of necessity, and that is why you are reading this guide, consider this
explanation of the problem. Many jobs happen inside the swarm library. If you want each member of a certain list to receive a
message every time period, you need to give Swarm a way to keep track of the members and the message. Since the objects at
which you want the messages aimed already exist and are objects, it is quite straightford to pass a Swarm object that object’s
name. Passing a Swarm object a method name is, however, more difficult. You need to give the Swarm object something
symbolic if it is to receive and remember it. You wouldn’t want the Swarm library to be built around the passing of character
strings, right? (Well, maybe you would, but pretend your answer is no!) If you pass the selector, you are passing a variable
type that the Swarm libraries can remember and use when they need it.
66
Chapter 9. Building Schedules
Each item in the list of agents, which is retrieved by the command
[modelSwarm getAgentList]
,
has the method drawSelfOn:. Here is the method drawSelfOn:, which can be found in
SugarAgent.m:
- drawSelfOn: (id Raster )r
{
[r drawPointX: x Y: y Color: 100];
return;
}
If the agent gets the message drawSelfOn:r, then the agent in turn tells the object
r
to use its
drawPointX:Y:Color: method to put the agent on the picture.
The importance of the selector becomes apparent after a study of the file
Object2dDisplay.m in the
Swarm space library. In
Object2dDisplay.m, we find this method:
- setDisplayMessage: (SEL)s
{
displayMessage = s;
return self;
}
This takes the selector and puts its value into an instance variable called
displayMessage
. The other
set methods in
Object2dDisplay have already set the variable
objectCollection
and
displayWidget
. So, floating around inside the Object2dDisplay instance, are instance variables that
can be put to use in scheduling the actions.
When the display method of
Object2dDisplay gets scheduled by the ObserverSwarm, this method
from
Object2dDisplay.m is called:
- display
{
[...some irrelevant lines omitted...]
// if we have a collection to display, just use that.
[objectCollection forEach: displayMessage: displayWidget];
}
The forEach: method in the Swarm library takes a selector as its first argument, and any parameters
needed by the selector follow, separated by semicolons. So, in this example, the
displayMessage
variable has been set as drawSelfOn and the
displayWidget
has been set as the
worldRaster
.
So when the display method executes, it passes to each object in the list a message that tells it to draw
itself on the
worldRaster
.
Almost all uses of the selector type in Swarm allow a variable number of arguments. It is important to
note, however, that these arguments are generally required to be objects. We would have some trouble if
the arguments were floating point values, for example. When such a case arises, one if usually forced to
write "wrapper" objects around floats in order to pass them to the Swarm library. For example, consider a
67
Chapter 9. Building Schedules
change in the problem faced by the hypothetical psychologists discussed above. Suppose instead of
dealing with
bill
and
susan
, they are instructed instead to set some variables inside themselves, such
as
idealTemperature
or
setLengthOfFeelers
(these are buggish psychologists, say). The
method in the psychologist class might have this interface:
- setTemperature: (float)temp And: (float)feeler;
Now, if you wanted the Swarm to schedule this setTemperature:And: method to happen every
time step, perhaps to "reinitialize" the objects to a "fresh" state, then you would be in a world of hurt. If
you need the temperature to be set at 37.3 and the feeler to be 54.1, you would be tempted to write this,
but you would be making a big mistake:
[modelSchedule at: 0 createActionForEach: listOfShrinks mes-
sage: M(setTemperature:And):37.3:54.1];
The createActionForEach: method is looking for something like SELECTOR:id:id at the end,
but this command instead gives it SELECTOR:float:float.
When you need to pass float values in this way, you may have to redesign your methods so that they can
take objects. For example, you might make a new kind of object to hold the values of those floating point
numbers. This new class is often called a "wrapper" class. If that new class, call it the
ParameterHolder
for discussion, is able to respond to methods like getTemp and getFeelr, then this problem could be
tackled by rewriting the setTemperature:And: method into something like:
- setParameters: holdingObject;
If you have an instance of ParameterHolder, called
aHolder
for short, then the psychologist can be told
to setParameters by a command like this:
[aShrink setParameters: aHolder];
Presumably, inside the setParameters method there are actions that get the values from the
aHolder
which is passed in, as necessary.
If you need to schedule a whole list of psychologists to reset themselves, the schedule command could be
written as:
[modelSchedule at: 0 createActionForEach: listOfShrinks message: M(setParameters):aHolder];
9.3. ActionGroups
An ActionGroup is a set of actions that are supposed to happen in sequence. The buildActions
method is often designed to first create an
ActionGroup and then to schedule that is be repeated every
now and then.
68
Chapter 9. Building Schedules
Consider the Swarm SugarScape again. Its model swarm has this buildActions method
2
:
- buildActions
{
[super buildActions];
// One time tick, a set of several actions:
// randomize the order of agent updates (to be fair)
// update all the agents
// kill off the agents who just died
// update the sugar on the world
modelActions = [ActionGroup create: [self getZone]];
[modelActions createActionTo: sugarSpace message: M(updateSugar)];
[modelActions createActionTo: shuffler message: M(shuffleList:) : agentList];
[modelActions createActionForEach: agentList message: M(step)];
[modelActions createActionTo: self message: M(reapAgents)];
// The schedule is just running our actions over and over again
modelSchedule = [Schedule createBegin: [self getZone]];
[modelSchedule setRepeatInterval: 1];
modelSchedule = [modelSchedule createEnd];
[modelSchedule at: 0 createAction: modelActions];
return self;
}
ActionGroup
s group together events at same timestep. Schedule then executes the actions. If there is only
one
ActionGroup in a schedule, then