breve Documentation: version 1.9 | ||
---|---|---|
<< previous | Chapter 2. "steve" Language Reference | next >> |
Certain variables have special meanings in steve. Their values are managed automatically by the breve engine and should not be assigned manually.
self (object)
.
This variable always contains the value of the instantiation in which the current method is being run. The variable is used most frequently to call other methods within the same instantiation. For example, an object of class Mobile could move itself with the call:
self move to (10, 10, 10). |
super (object)
.
This variable refers to the parent, or super-instantiation, of the instance in which the current method is being run. This variable is used most frequently in the same fashion as self, except that it runs the method in the superclass instead.
For example, in the Controller's iterate method, the superclass iterate method is often called: super iterate. This is because the Control class itself actually iterates the world, while user subclasses manage their own objects. After a user has run their own code in an iterate method, they ask the superclass to update the state of the world.
caller (object)
.
The caller is the object which called the currently running method. In the case of methods called automatically by the environment (init, iterate and callback methods, for example), the value is NULL.
controller (object)
.
The controller variable always refers to the simulation's controller instance.
The most simple expressions are simple assignments of literal values to variables. It may help to refer to the documentation on steve types before continuing.
Below are a few examples of this type of expression. In each case, the variable on the left will take the value of the expression on the right. If the expression on the right is not the correct type, it will be automatically converted if possible. If the conversion is not possible, an error will occur.
myInt = 4. myDouble = 12.345. myString = "Hello!". # If we assign a double to an int, it will be automatically converted by # truncating the decimal portion. In this example, myInt will take the value # 4: myInt = 4.8. # Likewise if we assign a string to a double or int. The variable will take # the number value of the string, according to the atoi() or atof() ANSI C # functions. Here the double will get the value 10000: myDouble = "10000 miles away.". |
Mathematical operators in steve function almost exactly the same as they do in C, although there are some additions to account for vector and matrix types.
The following binary operators are valid for int
and
double
types (the descriptions refer to x and y, as
though they were used in an expression:
x operator y
):
+
, addition
-
, subtraction
*
, multiplication
/
, division
%
, modulus (the remainder of x when divided by y)
^, power (x raised to the power of y)
Their functions should be self-explanatory, with the possible exception of modulus, which cannot be used with double types in C. When used with doubles, the result is calculated using the ANSI fmod()
function.
The following operators are valid for use with two vectors:
+
, vector addition
-
, vector subtraction
The following operators are valid for a vector and a double (although an
int
is automatically promoted to a double in this case):
*
, vector times scalar multiplication
/
, vector divided by scalar division
As in many languages, parenthesis are used to group expressions when the default order of operations does not compute the desired result:
# this is the default order, but we can make it explicit with parens x = x + (4 / y). # computes 4 / y first... # this is NOT the default order -- we need to force it x = (x + 4) / y. # computes x + 4 first |
Mathematical expressions are often used in conjunction with assignments in order to modify the value of a variable. A few examples of using mathematical expressions in conjunction with assignments follow:
x = x + 4. y = (1, 2, 3) / x. # assumes x is an int or double z = z + x^2. |
In addition to the mathematical assignment operators above, steve also support mathematical assignment operators. Mathematical assignment operators are used as shortcuts to perform a calculation and update the value of a variable simultaneously, instead of as two separate steps. These expressions are useful, but since they are only shortcuts for other expressions, understanding them is not critical.
The following mathematical assignment operators are available:
+=
-=
*=
/=
%=
^=
These operators are simply shortcuts for cases in which the left operand of the mathematical expression is also the location where the output of the expression will be stored. For example, the following expression pairs are equivalent:
a = a + b. # "a equals a plus b" can also be written as... a += b. # "a plus equals b" a = a - (2, 2, 2). a -= (2, 2, 2). |
steve also has "increment" and "decrement" assignment operators:
++
--
As in languages like C and Perl, these operators increment and decrement a variable by one, respectively. Unlike C and Perl, these operators may only be placed after the variable. As an example, the following expression pairs are equivalent:
x = x + 1. # updates the variable x by adding 1 x++. x += 1. # does the same... x++. y = (x += 1). # a little confusing, but sets both x and y to (x + 1) y = x++. # as does this. |
A number of internal functions (which are otherwise typically not used in breve simulations) are available for math-related expressions. Internal functions are called just like C functions: functionName(arguments).
sin(input)
gives the sine of the radian angle input.
cos(input)
gives the cosine of the radian angle input.
tan(input)
gives the tangent of the radian angle input.
asin(input)
gives the radian angle arc sine of input.
acos(input)
gives the radian angle arc cosine of the input.
atan(input)
gives the radian angle arc tangent of input.
sqrt(input)
gives the float
square root of input.
angle(a, b)
gives the float
angle in radians between vectors a and b.
max(a, b)
gives the maximum of floats
a and b.
min(a, b)
gives the minimum of floats
a and b.
cross(v1, v2)
gives the vector cross product of vectors v1 and v2.
dot(v1, v2)
gives the float dot product of vectors v1 and v2.
log(input)
gives the float
natural log of input.
randomGauss()
gives a float
random number with a Gaussian distribution.
transpose(input)
gives the transpose of the matrix input.
The following internal functions are used for testing float variables for special values which have meaning primarily to developers and plugin authors.
isnan(input)
returns 1 if the input is a "not-a-number" float value, 0 otherwise.
isinf(input)
returns 1 if the input is a float value representing infinity, 0 otherwise.
Random numbers are available in steve using the command random
. The syntax is random[ expression ]
, where expression is an expression of either
int
(Section 2.5.1), float
(Section 2.5.2) or vector
(Section 2.5.4). The value returned is always the same type as the expression. In the case of int
or float
, the returned value is a random value between 0 and the expression. In the case of a vector
expression, the returned value is a vector
in which each element is between 0 and the corresponding value of the expression. For example, a call to random[(10, 10, 20)]
returns a vector
with X and Y elements between 0 and 10, and the Z element between 0 and 20.
Note that random[intValue]
returns a value between 0 and intValue, inclusive, as opposed to the behavior that many C programmers expect in which the returned value is between 0 and intValue - 1.
Because many simulations use the origin (0, 0, 0) as the "center" of their world, it is often useful to obtain a random vector centered around (0, 0, 0). For example, if we want to move agents somewhere within an imaginary box surrounding the origin, we might use the expression random[(40, 40, 40)] - (20, 20, 20)
. This convention gives us a vector
with each element between -20 and 20. This type of expression appears frequently in simulations.
The values are produced using the standard C library random()
routine. The library is seeded with the current time when the breve application is launched. To explicitly set the random seed, you may call the internal function randomSeed( value )
, where value is an integer.
In the event that multiple breve simulations are launched simultaneously (typically only relevant in cluster environments), it may be necessary to pick unique random seeds for each simulation to prevent each of the simulations from giving the same results. Refer to the Controller method set-random-seed-from-dev-random for more information on automatically picking unique random seeds on systems which support it.
As discussed in the section on defining class methods, each method is identified by a name and may have any number of input arguments. The most simple method call to a method with no arguments is simply:
instance methodName. |
If the method takes arguments, each argument is associated with a keyword: the keyword identifies which argument will follow and what it's type is. This is somewhat different from C where the argument's type and meaning is specified by its order relative to other arguments. The steve method is more similar to Objective C and allows a more natural language structure to method calls and protects against arguments being passed in the wrong order.
To pass arguments to the method, simply precede the argument value with the keyword name. Consider a method move-object which takes a keyword to:
myObject move-object to (1, 2, 3). |
If the method takes more than a single argument, the convention is the same—just add the next argument afterwards. Note that the order in which the arguments are passed does not affect the method call, though it may affect the readability of the code. For example, the Control object implements a method to point the camera at a certain vector location from a vector offset—first we'll see the method definition, then how it's called:
# if the method is defined using: + to point-camera at location (vector) from offset (vector): ... # then from another method, we can call point-camera using the code below. # these two method calls are equivalent, though the first reads more # naturally. + to do-something-else: self point-camera at (0, 0, 0) from (100, 100, 100). self point-camera from (100, 100, 100) at (0, 0, 0). |
If you wish to call a method for multiple objects, you can use the method call syntax with a list of objects. Note, however, that the arguments to the list are computed for item in the list separately. This makes a difference in the following example:
# assume that mobileList is of type list mobileList = 10 new Mobile. # The random statement is evaluated for each instance, meaning that all the # instance go to different random locations, not to a single random location. mobileList move to random[(20, 20, 20)]. |
all
ExpressionYou can find all instances of a given class using the
all
expression. all
is given
the name of a class, and returns a list containing all objects of that
type.
# get a list of all mobile objects in the simulation myMobile = all Mobiles |
print
and printf
The print
and printf
statements are
used to print output from a simulation to the output log. Both of these
statements accept any type of expression, as well as multiple expressions
separated by commas. Also, since strings
may contain
embedded variables, you can format the output of variables however you'd like.
See the section on strings
(Section 2.5.7)
for more information.
The only difference between print
and
printf
is that printf
does
not automatically print a newline character. This
means that subsequent prints will continue on the same line (as though
the "return" key was never hit). This can be useful if you're trying
to produce output in a specific format, but is typically not desirable.
If in doubt, stick to print
Here are some examples of print
and
printf
:
# print two variables, side by side. print (self get-time), populationSize. # use a variable embedded in a string. print "the population size is $populationSize". # the following statements would produce the text: # A B C # D E F print "A B C ". print "D E F" # the following statements would produce the text: # A B C D E F printf "A B C ". printf "D E F" |
As in C, of course, users can use subexpressions as part of larger expressions. For example, you can use a mathematical expression as part of a method call, or a method call as part of a mathematical expression. Because of the syntax of steve , however, subexpressions frequently need to be parenthesized in situations where it would not be required in C. The following important rules apply to using subexpressions: If a method call is not the entire statement, it must be parenthesized. If you wish to assign the result of a method call, use it in a mathematical expression or use it as an argument for another method, for example:
myInt = (self get-speed). # correct myInt = self get-speed. # incorrect myInt = (self get-speed) + 5. # correct myInt = self get-speed + 5. # incorrect self set-speed to (neighbor get-speed). # correct self set-speed to neighbor get-speed. # incorrect |
All method arguments must be a single "unit"—arguments which are not simply a variable or literal value must be parenthesized.
This means that if you use mathematical expressions, instantiations or other method calls as input arguments to a method, they must be parenthesized. The first rule about method calls, of course, still applies:
self set-location to ((neighbor get-location) + (10, 10, 10)). # correct self set-location to (neighbor get-location) + (10, 10, 10). # incorrect |
![]() | For developer use only |
---|---|
Internal function calls are for use by breve and plugin developers only. |
A final expression type not discussed above is an internal functions. Internal function calls look just like C calls:
methodName(arg1,arg2, ... argN) |
Though internal function calls are the most direct access to the breve libraries and features, the included class hierarchy provides a formal interface to the internal functions such that user simulations should never use these internal functions. The only exception to this is for certain mathematical functions.
<< previous | breve Documentation table of contents | next >> |
Types in "steve" | up | Program Control Structures |