Snippets
FAQ for using SARL + SWI Prolog
This is a collection of questions/issues that arose from my teaching of Agent Oriented Programming, where I have assessments in SARL and SWI Prolog, all packaged with Apache Maven.
If you think a question is worth putting it here, please let me know, I am happy to add it! THANKS!
- FAQ for using SARL + SWI Prolog
- ECLIPSE
- SWI-PROLOG
- MAVEN
- SARL
- SARL is similar to Java but has different syntax in many places, how come?
- Seems my SARL application cannot find JPL!
- Strange error in CLI when using occurence on left hand side of assignments
- Can we document SARL code for JAVADOC?
- How do I control the log-level of the Logging built-in capacity?
- How can we know when an agent has been created fully after being spawn?
- Equality and identity comparison (==, ===, !=, !==) in SARL and checking for null: same as Java ?
- How to return two values? Pairs in SARL
- I cannot pass data to the Initialize of a Behaivor, occurrence.paramters is always empty!
- Cannot access agent owner of a skill in Initialize behavior, why?
ECLIPSE
How do I make ECLIPSE know about environment variables (e.g., SARL_VERSION)?
I can imagine there are other ways, but the way I made it work is by starting ECLIPSE from CLI with the variable exported already:
$ export SARL_ECLIPSE=0.7.2
$ ./eclipse-sarl
If you find another way that ECLIPSE can gather the environment variables (without re-defining them one by one), let me know!
SWI-PROLOG
MAVEN
How do I install a JAR dependency manually?
Suppose your application need version 1.2.0.7.2 of artifact sarl-agtcity-mw from group id org.bitbucket.ssardina-research, but for some reason it cannot be gathered automatically from the cloud.
Suppose you can get a hold of that dependency and obtain file sarl-agtcity-mw.jar. How do you install it in the repo? Here it is:
mvn install:install-file -Dfile=sarl-agtcity-mw.jar -DgroupId=org.bitbucket.ssardina-research \
-DartifactId=sarl-agtcity-mw -Dversion=1.2.0.7.2 -Dpackaging=jar
How do I tell maven to work offline (not check anything on the internet)?
Use the -o option for offline mode (e.g., mvn -o clean package): https://www.packtpub.com/mapt/book/application_development/9781785286124/8/ch08lvl1sec81/working-in-offline-mode
Note you will still need to build the system online at least one, so that your system has the chance to get all the dependencies and store them under ~/.m2/
Why maven is not downloading the sources of dependencies?
ECLPSE IDE seems to download all sources by default. To get the sources via CLI: mvn dependency:sources
To state the POM to get all sources (and javadocs) of dependencies, check this post
Error from Google Lirary related to a Java 9 class
The version of the maven-compiler-plugin should not be higher than 3.6.2 because the newer versions are using Java 1.9. And, it may cause problems during the compilation process.
In reality, the maven-compiler-plugin is not mandatory at all in the POM because Maven is supposed to download one when needed for compilation. If you encounter strange error related to the use of an Java 9 class from the Google library, then you have to specify the maven-compiler-plugin in order to avoid it:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.2</version>
<configuration>
<source>${compiler.level}</source>
<target>${compiler.level}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
How to assemble my whole SARL application in a JAR file?
You can use maven-assembly-plugin build pluin:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>BootMAS</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<!-- EXECUTIONS -->
<executions>
<!-- Assemble an application bundle or distribution from an assembly descriptor. -->
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
Note that with version 3.1.0 this may take quite longer to compile, as all dependencies are packaged into a single, often large, JAR file.
SARL
SARL is similar to Java but has different syntax in many places, how come?
Because it uses and builts on XTEND framework.
Seems my SARL application cannot find JPL!
There could be many reasons and it may depend on the OS you are using.
First of all, do you have the JPL package installed in the system?
- In Windows, it is easy as you can click to install JPL Java<-->SWI interface at installation time.
- You should get jpl.dll file in
%SWI_HOME_DIR%/binandjpl.jarin%SWI_HOME_DIR%/lib.
- You should get jpl.dll file in
- In Linux, you need to make sure
libjpl.soandjpl.jarare somewhere! If you cannot find it, then you may need to install JPL.- In Ubuntu, it is provided with package
swi-prolog-java. - In ARCH, you can generate it and install it using AUR package builder and
swi-prolog-gitpackage. Running the default PKG build file is enough to get JPL installed. - In MAC, we don't know how to make it work, as there is a glitch in one of the packages built for Mac... :-( [if you make it work, please let me know!]
- In Ubuntu, it is provided with package
Once JPL is in your system, you need to make the system is aware of it!
- In Windows, make sure:
- A system variable
SWI_HOME_DIRpoints to the root of SWI install. - System variable
Pathincludes%SWI_HOME_DIR%\binand%SWI_HOME_DIR%\lib\jpl.jar.
- A system variable
- In Linux, make sure:
export LD_PRELOAD=libswipl.so:$LD_PRELOADexport LD_LIBRARY_PATH=/usr/lib/swi-prolog/lib/amd64/(or whereverlibjpl.sois located)
With this, your SARL application should be able to recognize where JPL is (hopefully!) :-)
You may also refer to the instructions of the SARL Prolog Capacity
Strange error in CLI when using occurence on left hand side of assignments
Consider this code:
on CarArrivedPercept {
cars.get(occurrence.car).floor = occurrence.floor
}
We know that occurrence is static, so cannot be changed. However, in the above code, occurrence.car, is not being changed/assigned, but just used to refer to another entity where assignment is performed.
However, SARL compiler will think that you are changing static element occurrence and complain with error. Instead do this:
on CarArrivedPercept {
val n = occurrence.car
cars.get(n).floor = occurrence.floor
}
Can we document SARL code for JAVADOC?
Presumably yes, but I was not yet successful (have not tried much though!). Check this post: https://groups.google.com/forum/#!topic/sarl/E_mhpFWyBFo
How do I control the log-level of the Logging built-in capacity?
Use setLogLevel() as explained here: http://www.sarl.io/docs/official/reference/bic/Logging.html
There used to be a bug in that debug() was passed to the system logging which if it was at level INFO it would not display it.
It should now be fixed; see this post: https://github.com/sarl/sarl/issues/803
How can we know when an agent has been created fully after being spawn?
An event AgentSpawned will be emitted when an agent has been created and can be handled, say by a coordinator, to know the agent is now alive! Fo example:
on AgentSpawned {
info("Agent {0} of type {1} has been created successfully and is now alive!",
occurrence.agentIdentifiers, occurrence.agentType)
}
Equality and identity comparison (==, ===, !=, !==) in SARL and checking for null: same as Java ?
SARL's developer states that the mapping of the operator from SARL to Java are:
a === bbecomesa == ba !== bbecomesa != ba == bbecomesa == null ? (b == null) : a.equals(b)a != bbecomes!Objects.equals(a,b). This is null-safe (part of Google API) and the code of the function isa == b || (a != null && a.equals(b))
It is always better to test valid against null with the === or !== operators.
Because the SARL == operator is mapped to the Java equals() function, and the === and !== operators to the Java == and != operators, it is better/safer, and a best practice, to use === and !== when one of the operands is of primitive type, e.g. null, number constants, primitive type variables. These operators are not replaced neither operator_equals nor operator_notEquals within the Java code.
Ususally, the SARL compiler generates a warning to push you to use === in place of ==. But with null == value, an ambiguous call error occurs before the warning is generated.
I believe SARL mapping this is because SARL comparison operators follow the which means that:
- In Xtend the equals operators (
==,!=) are bound toObject.equals. - Java’s identity equals semantic is mapped to the tripple-equals operators
===and!==in Xtend.
Check xtend doc here for more details and SARL doc here.
Note directly from SARL developer (Sept 2018): SARL extends a part of Xtend dialect in order to have benefits of several background features, such as the validation tests for type inheritance. Since Xtend and SARL uses Xbase, a large part of the syntax is the same, especially within the blocks of code. (The rest of the syntax is defined in parallel. SARL was inspired by languages such as Scala, Python and Ruby. Several bugs or incoherencies of Xtend are fixed in SARL.
There is still a bit of an issue inside the Xbase library; check this https://github.com/sarl/sarl/issues/852#issuecomment-420842088
I have created an issue regarding null == value: Issue #854.
According to the associated discussion within the Xbase group #300, the error message will be updated to push the developers to use ===.
How to return two values? Pairs in SARL
Java comes with a Pair<A,B> class to build an object for storing two values, nicknamed "key" and "value", but they have no meaning as key/value. It comes useful when a method has to return two values instead of just one. For example, the following function returns the next floor and direction that an elevator has to serve:
def kb_getNextJob() : Pair<Integer, Direction> {
...........
}
As of Java 8, and as part of JavaFX, Java provides this Pair<A,B> class; check here and here.
Note Pairs are different from Map, which can be seen as a collection of Pairs and with a proper key/value semantics.
There exist more advanced implementations of Pair, for example from Apache. See here, here and here.
SARL itself have compact syntax do deal with Pair, by using a -> b to create a Pair object (a,b). There are also compact ways of manipulating Collection and Maps.
Check SARL documentation on that here.
I cannot pass data to the Initialize of a Behaivor, occurrence.paramters is always empty!
From SARL developer in this post](https://groups.google.com/forum/#!topic/sarl/E0TuX-V123U):
Currently, there is no way to set the occurrence.parameters values with the current API.
The Initialize event is fired by the registerBehavior function. As you could see, this function does not provide a mean for passing initialization parameters.
I think the ability to set the Initialize parameters when registering the behaviors is a missed feature from the SARL API.
Until it is solved (see open issue here), you could use the following work around:
behavior MyBehavior {
var initParam : Object[]
new (owner : Agent, initParam : Object*) {
super(owner)
this.initParam = initParam
}
on Initialize {
// Do something with this.initParam
}
}
agent MyAgent {
uses Behaviors
on Initialize {
var beh = new MyBehavior(this, "p1")
beh.registerBehavior
}
}
Note that because registration happens after the creation of the behavior module, the initParam will be available at time of Initialize execution.
Cannot access agent owner of a skill in Initialize behavior, why?
Summary of See this thread
The owner of the skill is set when the skill is attached to the agent. It means that the owner cannot be known within the constructor of the skill. The function install is invoked just after the skill is installed into the agent.
So:
new {
super()
assert this.owner === null
}
def install {
assert this.owner !== null
}
Importantly, the initialization (via Initialize event) is not at creation time (constructor) but when the entity is attached to the agent.
Within SARL developers' perspective, constructor statements should be redefined only if you want to set the value of a field that is final (val keyword), because it is mandatory regarding the semantic of the val keyword.
Consequently, the best practice is that all initializations should be within the on Initialize. They should avoid constructor definition.
So, the "clean" way to access the agent owner is in the install method:
skill SWIJPL_KB_Prolog implements KB_Prolog {
var module_name : String
def install {
module_name = this.owner.ID.toString
}
...
}
You can clone a snippet to your computer for local editing. Learn more.