Shica – Improving the Programming Experience for Agent-Based, Distributed, Physical Computing Systems
Abstract
Agent-based and distributed computing systems play an important role in many fields. Programming these systems can be annoying because of the complexity of managing multiple asynchronous processes and state transitions, sometimes hidden inter-dependencies between program elements, and (often) unnecessarily terse, un-intuitive syntax.
In this paper we describe the design and implementation of Shica, an experimental language designed for physical computing that is fun to program. Shica unifies state-based, event-based, and distributed programming along with some elements of context-oriented.
We informally evaluate Shica’s characteristics including its suitability for deployment on resource-constrained, embedded devices and its contribution to improving the quality of the programming experience by maximizing scope, economy, and elegance of expression.
Keywords and phrases:
Programming Languages, run-time Systems, agent-based ProgrammingCopyright and License:
2012 ACM Subject Classification:
Software and its engineering Multiparadigm languagesEditors:
Jonathan Edwards, Roly Perera, and Tomas PetricekSeries and Publisher:
Open Access Series in Informatics, Schloss Dagstuhl – Leibniz-Zentrum für Informatik
1 Introduction
Agent-based and distributed computing systems are used in various fields. Agent systems are used in applications such as simulation, chat-bots, and smart grids. Distributed computing is used in applications such as cloud computing, big data processing, blockchain, and distributed databases. In these applications the implementation and management of multiple asynchronous processes that change depending on the system’s state can be a challenge. As systems evolve, the addition of new states and processes to the system increases complexity and, without proper language support, systems can become increasingly difficult to understand and maintain and therefore less reliable.
In the case of agent-oriented programming, many languages use the rule-based Belief-Desire-Intention [20] (BDI) model. Rule-based languages are complex because they include conditional branches of one or more event variables. Languages based on BDI use a procedural representation for the conditions and subsequent processing that can span multiple contexts, potentially leading to difficultly understanding and controlling system behavior. Often the processing simply changes the “state” of the system, with computation progressing trough a series of states held within one or more independent state variables. Each state variable has an associated set of possible states that it can assume. Tracking state changes and managing the processing according to state changes can be difficult because of the complex patterns and interactions between states. In addition, variables or functions used in the current and next states are often managed by class objects or global variables, which can create dependencies that are spread across the entire program and are consequently difficult to manage.
Various programming paradigms and techniques, with their associated models and languages, have been invented with the intention of improving the programmer’s experience when designing, building, understanding, and maintaining agent systems. Some examples include state-based and event-based programming languages, and languages with explicit support for distributed computing or communication.
Each language has strengths and weaknesses which lead to programmers experiencing ease or difficulty when expressing the behavior of parts of their systems. For example, a state-based language might provide a mechanism for changing from one state to another along with a mechanism to perform specific actions when entering a new state. Programmers wanting to perform different actions when entering a particular state, depending on the previous state, would rapidly experience frustration as they add their own variables to record the previous state and multi-way conditionals to choose which actions to perform as a new state is entered.
This paper presents Shica, an experimental language that we are using to explore potential language and behavioral solutions to some of these issues, and our qualitative evaluation of its contribution to improving the programming experience.
Shica is a state-based, event-driven, distributed programming language that provides multiple asynchronous processes, concurrent event processing, and explicit state transitions.
Our evaluation includes the suitability of Shica for its intended purpose which encompasses two general concerns: is it feasible for use in resource-constrained environments, and does it improve the programming experience compared to related languages?
The remainder of this paper is organized as follows: Section 2 presents related work and explains some concepts and context needed to understand Shica. Section 3 explains and justifies some of our design goals. Section 4 evaluates the strengths, weaknesses, and affective characteristics of Shica and several other languages in the context of program that benefits from language support for states, events, and distributed communication. Section 5 discusses how well we think Shica meets its design goals. Finally, Section 6 presents concluding remarks and our intentions for future work.
2 Related work
To date, state-based (agent-oriented) programming, event-driven, and distributed computing techniques had significant influence on distributed, agent-based systems.
State-based programming is inspired by finite state machines, which have long been an essential tool for building automated systems during design (because of their formal characteristics) as well as implementation (because of the simplicity of representation). Many programming languages have been designed that make states and/or transitions between states part of the programming paradigm, in some cases making one or both of them into first-class values. Arbitrary actions associated with states and/or state transitions gives the programmer great flexibility to implement complex solutions expressed as a finite state machines. Some languages also allow the response to stimuli and the choice of next state to be dependent on several criteria, including (but not limited to) the current state, allowing a powerful form of context-sensitive programming.
Several languages have gone further, in particular those associated with the belief-desire-intention [20] (BDI) model. It allows multiple states to co-exist as independent state variables, with transitions being handled orthogonally between variables. Actions are associated with transitions between states.
Many “agent-oriented” languages implement the BDI model.111While object-oriented programming focuses on objects with methods and variables, agent-oriented programming focuses on agents with interfaces and message communication functions. Agents are considered abstractions of objects, and the messages that are sent and received are interpreted in a way that depends on the type of receiving agent. AgentSpeak(L) [19] laid the foundations for subsequent derivative languages. Jason [4] made multi-agent system development practical by implementing AgentSpeak in Java, and LightJason[2] further improved performance and flexibility by introducing parallel execution and “lambda” expressions. ASTRA [6] adopted static typing and a syntax close to Java while maintaining the simplicity of AgentSpeak, and Gwendolen [8] is designed to formally verify the behavior of agents. Finally, GOAL [13] enables high-level decision-making by declaratively defining goals and emphasizing symbolic reasoning.
Linden Scripting Language (LSL) [15] is a state-based programming language that does not follow the BDI model. LSL is used in the Second Life [16] and OpenSimulator [18] virtual environments to add “scripts” to virtual objects. The dynamic interaction of those objects with users, other objects, and the environment in general is all controlled by LSL scripts. To encourage artists and other creative non-programmers to use these environments, LSL was designed to be simpler to understand than the BDI-based languages. LSL scripts are state-based, but at any given time the entire script can only be in one of the possible states. The response of an object to an external or internal stimulus is based on the current state, and so LSL provides a form of system-dependent context-oriented programming.
Shica is closest to LSL in the way it provides states to the programmer. Its response to events (see below) is state-dependent, like the languages above. Transitions to a new state are initiated explicitly in Shica programs, meaning they can be conditional on any criteria the programmer chooses.
Event-driven programming is a technique in which the behavior of a system is determined in response to external stimuli presented as events. Events can be internal (timers, messages received from other components of the same program, etc.) or external (remote message received, hardware interrupt indicating an environmental change, user interface button clicked on a graphical display, etc.). Support is often provided as a library or framework, or as part of the language paradigm. Applications such as graphical user interfaces must respond to unpredictable, asynchronous user interactions and event-driven programming is therefore widely used in GUI design, for example in tcl/tk [7] and Swing [10]. Often an event loop monitors sources of stimuli and, when one is detected, executes the corresponding event handler. This technique is also useful for continuing an activity after an asynchronous background task has completed, for example in web browsers waiting for page elements to finish loading or a request made over a web socket to receive a reply. Asynchronous behaviour in JavaScript [17] is provided by its event loop.
Giotto [12] is a time-triggered programming language for hard real-time embedded systems in which tasks are executed at a predetermined rate. It has no states, but several concurrent tasks can be grouped into a “mode”. Switching from one mode to another alters the mix of tasks currently running in the application. XGiotto [22, 11] extends this with asynchronous events.
LSL [15] combines state-based with event-driven programming. Scripts are mostly dormant, waking up when an event handler is triggered by a timer or external condition (the object containing the script is touched, a message is received from another script or object, etc.).
Shica programs are also event-driven with sources being internal (such as timers) or user-defined (such as from a hardware driver connected to an interrupt pin or comparator). Like LSL, each Shica state has its own set of event handlers which are enabled when the state activates. Shica supports time-driven programming through the use of recurring timer interrupts, although without the formal real-time guarantees of languages such as Giotto.
Distributed programming allows multiple agents to work together locally or over a network.
Nodes communicate through message exchange to perform a task cooperatively. The Actors [1] model is often used, with distributed processing taking the form of a sequence of message exchanges which can include request-response patterns. However, the model is difficult to adapt to dynamic group generation and environmental changes because it assumes a fixed pattern of communicating processes. Languages that support explicit or implicit distributed programming are often based on the Actors [1] model in which each independent, communicating node is treated as a primitive component of the concurrent computation.
A number of distributed programming languages have been investigated since the 1980s including Obliq [5] which let computations roam over a network and Oz [23]/Mozart [24] in which object location is transparent to the programmer.
Perhaps the most significant contemporary distributed programming language is Erlang [25], a pure, concurrent, functional language which is used by several telecommunications companies to provide global mobile telecommunications infrastructure. Internally an Erlang program is typically made from hundreds of concurrent processes exchanging messages sharing a single runtime system. An Erlang runtime system can subsequently become one node in a distributed Erlang system. Messages are passed between these nodes in the same way as they are between local processes. Elixir [21] is descended from Erlang, runs on the same machine, and introduces a more familiar syntax and the ability to assign to variables more than once.
Go [9] is designed to support massively parallel distributed computing and its goroutines and channels provide distributed communication and computation based on the communicating sequential processes [14] (CSP) model.222In the CSP model both reads and writes are synchronous in contrast to the Actors model in which receives are synchronous but sends are asynchronous.
Shica supports distributed computation through Actors-like message sending. Shica agents can join one or more communication groups and then broadcast messages to a group. Message reception is an event and handled like any other.
Unlike other agent-based systems, Shica provides a filter mechanism for events handlers. A handler can specify predicates in its parameter declarations, all of which must be met for the handler to be invoked. This provides a variation on the publish-subscribe model of distributed computation [3] that has no centralized broker, with filtering performed in the client rather than a broker.
3 Design goals
This section outlines what we would like to achieve with Shica and some of the motivations behind our goals.
3.1 State-based system model
Figure 1 shows an example LSL script. When its object is reified in the virtual world it says “Hello, world!” in local chat. When clicked it alternates between two different responses, by alternating between two different states in which the same touch event is handled differently.
Shica is inspired by LSL. It uses a similar state-based modal system model, and uses a C-like synyax with lexical scoping and static typing. Shica and LSL both have explicit state transitions and so naturally support finite state machine (FSM) model of computation.
Figure 2 shows an example Shica program. Each state contains one or more event handlers that specify corresponding computations and state transitions.
This clearly separates the computation related to each state in the code and the flow of state transitions becomes clear, making it easier to understand and debug the application’s behavior. Also, because the code is divided into blocks for each state, we believe it is easier to modify and expand as the system evolves.
Unlike LSL, Shica adapts state-based event-driven programming to applications running on real physical devices rather than virtual objects that exist only in a virtual world.
3.2 Multiple event actions and conditions
JavaScript [17] allows multiple handlers to be defined for the same named event, as illustrated in Figure 3. In LSL, only one handler for a given event in each state can be defined. Conversely, Shica allows multiple handlers to be attached to a given event within a single state as shown in Figure 4. Using a mechanism inspired by predicate dispatch, handlers can specify a condition based on their parameter values which must be met for the handler to be invoked when their event is triggered.
In the state called eventMaster, two handlers are described for the event called button which is triggered whenever a button is pushed. One handler is conditional on the predicate val == 1 being met, meaning the button must have just been pushed. The other is predicated on the condition val == 0, meaning the button was just released. This allows the programmer to separate various cases of handling for a single event based on arbitrary predicates involving the event’s parameters and/or global variables.
Using state-local variables, such as debugging in Figure 4, it is possible to share data between events and the conditions that filter event triggering. This allows flexible programming with some of the potential of BDI.
In LSL, all events are stored in a unified queue and executed serially in a single thread. In Shica, event processing is concurrent and so, even if heavy load is encountered or if one event handler takes unusually long to complete, newly triggered events will be handled without significant delay. However, because processing is performed concurrently, access to state-local variables can cause data races.
3.3 Distributed Programming
We appreciate the simplicity of LSL’s “chat” model of communication between objects and scripts. Shica is designed to support physical computing and so a similar mechanism, based on wireless radio communication, is needed.
Shica’s event functions include delivery of remote messages broadcast over Wi-Fi. Groups are created dynamically and allow events to be exchanged and shared between multiple physical devices.
A group has a single leader which manages group membership. A group is joined when the program creates and initialises an action for the wifiGroupReceived event. The parameters passed to the initialization of the action include the IP broadcast address of the local network, a port number, a group ID, and a string representing a “password” needed to join that group. For example,
joins or creates group 42 on the local private network using port 6000 and password “shh!” (because it is a, badly-kept, secret).
An event can be triggered in all group members by sending a message
where -1 is a bitmap indication which group members should receive the event trigger (in this case, all of them). The triggered event is handled using an action of the form:
where from is the sender’s ID, scope indicates if the message was broadcast, sent from the local process, or sent from a remote process, and data is a single byte of data (very little, but sufficient for testing the ideas).
An complete example of a distributed application using this mechanism will be presented in Section 5.
4 Evaluation
Shica is a rapidly evolving language and a rigorous, comparative evaluation would be premature. This section presents our evaluation of the current version of Shica through two lenses, quantitative and qualitative. Firstly, is it quantitatively feasible for use in resource-constrained environments? Secondly, does it offer features that could qualitatively improve the programming experience compared to related languages?
4.1 Quantitative evaluation
We evaluated the current version quantitatively for size, to estimate its suitability for use in embedded devices.
The sizes of the compiler and the VM are 98,304 bytes and 49,152 bytes, respectively, built on an Apple M2 machine by clang using option “-Os” to minimize code size. Many micro-controllers use a similar ARM-based architecture and we therefore consider 50 kilobytes to achieve the goal of a runtime system that can fit into a small, embedded device.
The size of the radio group example program is 715 bytes of bytecode and 36 lines of source code. We estimate about 20 bytes per line of Shica source. Even on a very small device with 32 kilobytes of memory we estimate supporting a Shica program of more than 1,600 lines of source. A significant amount of functionality can be expressed in that many lines.
4.2 Qualitative evaluation
We evaluated the current version of Shica qualitatively according to both general features and the three paradigms that Shica aims to support.
Quantifying the experience of programming is difficult, especially when the relevant metrics include the amount of fun and joy experienced by the programmer, or how annoying the practice of programming can be. Affective reactions to programming such as these are also highly subjective. Reasons for finding programming fun, or a joyful and rewarding experience, might include personal growth via learning and acquisition of new skills, the achievement of creating useful automation or games, overcoming technical challenges to solve difficult algorithmic or numerical problems, or social aspects such as collaborating with a team on a large project.
Reasons might also change over time as a programmer gains experience and the technical challenge of programming diminishes, perhaps leading to satisfaction arising from the implementation of elegant and robust solutions, written in clear and concise code with little wasted expression. Since the latter aspects of programming are easier to estimate objectively, and because they certainly contribute to the reasons enumerated in the previous paragraph, we will concentrate on the ability of a programming language to enable elegant and concise expression of the programmer’s intent. The languages under consideration will therefore be judged based on estimations of their strengths and weaknesses with respect to scope, economy, and elegance of expression.
We believe most programmers would agree that writing programs in a language with appropriate scope, economy, and elegance empowers them to express new concepts quickly and easily, and is therefore an objectively better experience than using a language that is deficient in one or more of these aspects.
4.2.1 Empirical evaluations of programming experiences
We implemented a simple radio button group333A “radio button group” is named after the buttons that used to be on analog radio receivers to select the “band” of operation (long wave, medium wave, short wave, etc.). Since only one band can be tuned at a time, pressing any button will automatically disengage the previously engaged button. (RBG) application in Shica and three other languages representative of state-based, event-based, and distributed programming. Implementations of this application can benefit from state management, event handling, and distributed communication features of the various languages. The strengths and weaknesses of each language were assessed in the context of the RBG application. Informal observations were also made of the potential for “fun” and “annoyance” when using each language, its environment, or its features for pragmatic connection to the user or the real world.
The RBG application itself clearly benefits from state management, with a single state dimension containing two states for each button being sufficient to reflect whether it is active or inactive. Several events would be useful for example to deliver button presses, locally activate the indicator, and remotely deactivate any previously active indicator. Distributed communication is useful as a mechanism to deselect buttons and to allow them (whether virtual or physical) to be loosely coupled, with new buttons added trivially to the group.
We begin with Shica to provide a point of reference for the relative strengths and weaknesses of the other languages. From state-based languages we chose LSL, from even-based we chose JavaScript, and we chose Erlang to represent distributed programming languages. Listings of the RBG application written in each of these languages is included in Appendix A.
4.2.2 Shica
Figure 9 shows the RBG implemented in Shica. Identical code runs on three physical devices. Each device uses a momentary push button to activate a virtual radio button and a light-emitting diode to indicate which radio button is currently active. Group communication over Wi-Fi is used to ensure only one button is active at a given time. Figure 5 shows the Shica application running on three Raspberry Pi Zero 2 W single-board computers.
Strengths.
Shica supports a single implicit state variable with one active state per agent, which is sufficient scope for this application. State declarations and state changes both have concise, economical syntax. All per-state information is collected in one place within the state definition. Two statements, one for the button and another for the Wi-Fi, both initialize the corresponding hardware and enable the delivery of events relating to that hardware, helping with economy of expression. The static qualifier on events gives them global lifetime, removing the need to re-initialise the same event each time a new state is entered which also helps with economy of expression. Global event lifetimes also remove the need to use global variables to communicate initialisation or other information between states that reuse the same event. The C-like syntax will be familiar to many programmers. More advanced users can easily extend the implementation with their own modules and corresponding events opening the door to wider scope and more elegant programs.
Weaknesses.
Applications that require more than one state variable would not be well served by Shica; the programmer would have to simulate additional states using variables and conditional statements which is a lack of scope leading to uneconomical and inelegant programming.
Users cannot define their own events (without modifying the implementation) to use freely in their applications. Events are limited to those provided by the core implementation or those added by various modules.
The group communication mechanism is insecure. It does not currently provide a service for verifying trust between nodes or for generating shared secrets to help the programmer implement their own verification mechanisms. Although not illustrated in the RBG example, this lack of scope has serious consequences for economy and elegance if secure communication is required.
Messages in the Wi-Fi module are limited to integer data. String data would be preferable, a simple change, and we are considering that for the future. There is no support for pattern matching or parsing of incoming messages to extract commands, arguments, etc. This would also be added when messages can contain arbitrary text. Finally, remote messaging should really be unified with events so that together they behave like method invocation in a distributed object-oriented space.
Fun.
Controlling hardware devices is often a source of immense motivation and fun for novice programmers. Built-in management of Wi-Fi communication and group membership makes loosely coupled systems easy and fun to implement in Shica.
Annoyance.
Services and events are provided by modules such as GPIO and Wi-Fi radio. Each module has its own set of initializations which enable both the hardware and the associated events, which is sometimes non-intuitive. Some module names are far too long (e.g, the Wi-Fi one).
We identify many weaknesses and several shortcomings with Shica, but this could be due to our familiarity with it. Several of them could be addressed quite easily and perhaps fall into a category of features that are desirable in a system with adequate scope but which remain unimplemented because our own applications have not yet required them.
4.2.3 Linden Scripting Language
Figure 6 shows the LSL RBG application running in SecondLife. Figure 10 shows the RBG implementation in LSL. Identical code runs in any number of button objects in the virtual world that are within broadcast communication distance (20 virtual meters) of each other. Cloning more button objects immediately makes them part of the group.
Strengths.
LSL provides a single global state per script which is sufficient for the radio group application. State definitions and changes are economical and elegant with a clear, easy-to-understand syntax. LSL provides many events that encompass all potential interactions with objects and event handling is mostly intuitive. Private communication can be arranged by choosing a non-zero channel number of which 4 billion are available (channel identifiers are 32 bit integers) which is an economical although not very elegant solution to privacy due to its “security through obscurity” approach.
Weaknesses.
Elegance suffers because, Like Shica, multiple states are not built in to the language and would have to be simulated by the programmer. Economy suffers because explicitly enabled events such as listen (enabled with llListen()) are disabled on every state change and must be re-enabled using identical, redundant code on entry to every state that needs them.
Variables and functions are strongly typed which sometimes leads to annoying interfaces (e.g., a list can store values of any type but the getter function for an item at a particular index must specify explicitly the type of value that is expected at the index being retrieved). This scope issue leads to both poor economy (e.g., piece-wise disassembly of lists) and poor elegance (e.g., trying to iterate through a list containing unknown types).
Communication is (relatively) secure only by obscurity and there is no built-in mechanism to obtain a secure channel. This lack of scope leads to cumbersome, inelegant ad-hoc mechanisms to obtain quasi-private channels, and to inelegant and uneconomical additional code that is required to verify the authenticity of communications.
Events cannot be filtered according to their parameters. A couple of exceptions, related to message delivery events, offer only limited filtering by channel number, the sending object’s name or UUID, or by the text contained in the event, which is useless even in an application as simple as the RBG (which can make use of only the channel filter).
Event handlers cannot be shared between states which introduces redundancy and the annoyances and unreliability that comes with it. Variables are only global or local to functions; there are no state-local variables. Together these two limitations make some kinds of complex logic difficult to implement.
Messages are simple strings. There is no built-in support for pattern matching, predicate dispatch, or parameter extraction from within messages. These failures in scope lead to the programmer having to serialise outgoing message arguments into each text message, then parse incoming messages and deserialise any embedded parameters which is inefficient and inelegant. Programmers cannot define their own events, and events are not unified with inter-object messages to behave more like remote method invocation.
Fun.
Programs run in an environment that is naturally dynamic where things can react physically (to collisions or being poked by the user, for example) by moving, changing appearance, vanishing, exploding, etc. Similarly to Shica’s support for physical computing, this visual aspect can be a motivating and fun environment in which to program, especially given the ease with which so many kinds of interaction can be accomplished in LSL.
Communication between different scripts and objects is very easy, using an intuitive text chat mechanism that is broadcast to all listeners that are in range. This allows objects to be controlled by typing text commands explicitly, which is itself fun but is also a practical way to debug inter-object messaging easily.
Annoyance.
To guarantee that a private channel number really is not being used by another user or another application, necessitates additional, explicit coding by the programmer when such verification is needed.
Programs are usually written using the built-in code editor which lacks most of the convenience features of modern text editors and can be unpleasant to use.
Many of the built in functions have names that are too long, which is a trivial complaint but it sometimes forces the programmer to write a lot of letters to achieve something that is very concisely expressed in other languages.
The event model can be restrictive, limited to interactions in the virtual world and to responses from a few external sources (e.g., responses to database queries, HTTP requests, or reading text from a text file stored inside an object).
There is no support for message encryption and, if required, it would be implemented explicitly (e.g., XOR with a pseudo-random bit stream from a linear feedback shift register) in LSL, a language not designed for low-level string manipulation. Creating shared quasi-secrets based on some common characteristic (such as the object owner’s UUID) is awkward and a common, but not standardized, practice.
4.2.4 JavaScript
Figure 11 shows the RBG implemented in JavaScript running in a web browser. Identical code runs in any number of tabs, each tab presenting a single button within the radio group. Adding another tab running the same code in the same browser immediately adds its button to the group. Figure 7 shows the RBG application running in three windows of the same web browser.
Strengths.
JavaScript has a large variety of built-in features that simplify many kinds of programming problem. Due to its simple and flexible object representation and first-class functions as object attributes, these built-in features are easy to use and integrate well with the language. This brings a lot of useful scope, economy, and elegance to JavaScript programming. For example, crypto-quality numeric identifiers for the buttons are easy to generate in the RBG example and inter-process communication within a browser-local group is easy using a BroadcastChannel. Similarly, arbitrary event handlers can be added to any object as a property holding an anonymous function and then later invoked as normal functions.
Sending and receiving inter-process messages is easy with command names and arguments serialised automatically, in this example as a dictionary holding the type of the message and the id of the sender. This affords almost unlimited scope in the kinds of message content that can be exchanged, and brings economy and elegance to the program.
An event loop is built into the language and used for many activities that an application could benefit from, especially asynchronous ones. Events are delivered to applications in a unified way, as function calls made through object attributes.
Weaknesses.
State handling is not built in to the language, but is relatively easy to simulate (the isActive global variable in our example). However, the code tends to be disconnected and scattered in various parts of the application and is not automatically coupled to state change-related messages or events (in our RBG example we explicitly send the buttonPressed message and then set the isActive simulated state variable to true).
Message decoding is better than in LSL (commands and arguments are deserialised into objects automatically) but the lack of filtering on received messages forces the programmer to write their own message “dispatch” using conditionals.
Fun.
Similar to LSL and Shica, the browser environment offers visual and interactive components that can be highly motivating and fun for programmers, from simple buttons and shapes to rich graphics via canvases and WebGL.
Objects in JavaScript are very simple and flexible, and powerful as a result. The language is fun to program in and supports imperative, functional, and object-oriented styles in natural, economical, and elegant ways.
Annoyance.
Remote communication (between browsers or computers, not shown in this example) uses different mechanisms and paradigms (e.g., WebSockets) compared to the local communication shown in this example. Location transparency can be achieved because of the flexibility of the JavaScript language, but the programmer would have to provide their own wrappers for the purpose.
To make visual or interactive things the programmer has to know several internal details of the browser DOM. Modern JavaScript uses anonymous functions heavily in anything related to events or the event loop using syntax that can be confusing for beginners or even expert (non-JavaScript) programmers.
4.2.5 Erlang
Figure 12 shows the RBG implemented in Erlang. Instead of visual, interactive controls the program has a small three-line test harness that simulates buttons being pressed. The program instantiates three buttons each of which runs in its own process, sharing code with the other button processes. Figure 8 shows the RBG application running in the Erlang interpreter.
Strengths.
Erlang has strong support for messaging between processes. Message sending syntax is concise and pattern matching on received messages particularly convenient for decoding their content, making the messaging part of programs economical and elegant.
Weaknesses.
States and state changes are not supported by the language directly and the programmer must build their own model of states and transitions using global variables or local parameters. There is no built-in event processing loop either, and this must also be implemented by the programmer. This lack of scope can lead to loss of economy and elegance (and reliability) as redundant code is repeated, either to duplicate event dispatch conditionals within different states or to duplicate conditionals checking the current state within one or more functions acting as an event loop.
Group membership and communication has to be modelled by the programmer. In this example we create a list of processes to represent each “agent” button within the group, and then iterate over the list to simulate broadcasting the “off” message to each of the buttons before re-activating the one that was just “pressed”.
Fun.
Applications that lend themselves to parallelism and distributed processing, especially at a fine granularity, are very fun to write since creating, communicating with, and destroying processes is so easy and efficient.
Annoyance.
The most obvious potential annoyance, for non-Erlang programmers wanting to read or use the language, is the syntax which is far from the familiar C-like syntax of many other popular languages.
While relatively economical and elegant, user-defined event loops can be confusing for non-Erlang programmers (except perhaps for Lisp programmers) because of the use of tail-calls for iteration and accumulators in parameters to convey persistent information, such as state, from one iteration to the next.
Erlang’s ease of writing fine-grained, loosely coupled distributed programs also tends to encourage the programmer to distribute code associated with each state throughout the program, rather than collecting it neatly in one place as we see with the languages that provide support for state-based programming.
While Erlang does have a graphics system the amount of boilerplate code needed to create a window with three LEDs and three buttons is annoyingly large. We opted for a terminal-based simulation to limit the code to those parts associated primarily with states, events, and inter-button communication, and also to avoid several pages of listing just to create an interactive display. In our opinion Erlang falls behind the other languages considered here in terms of potential to provide a fun and motivating programming environment offering an easy path to creating simple visual, interactive, or physical computing systems.
5 Discussion
Counting only meaningful lines of code (ignoring blank lines and those containing only punctuation) in the example RBG application, the most economical languages of the four tested appear to be JavaScript at 22 LoC and Shica at 23 LoC. This is interesting because the two languages have very different characteristics.
JavaScript is a dynamically typed language that combines functional and object-oriented paradigms. It uses functions (anonymous, bound either to a global name or to a named slot within its dictionary-like objects) for all active behavior. The programmer simulates states using conditional statements that test the value stored in a global variable and transitions as assignments to that variable.
Shica is a statically typed language with an imperative programming style. States and state transitions are managed by the language, and Event handlers look a lot like functions but are not.
Which of the two provides the better programming experience? We think it depends greatly on personal programming style and taste.
Programmers from a Lisp or Smalltalk background might be drawn to the flexibility that arises from the simplicity and generality of JavaScript’s dynamic typing, polymorphic functions, and dictionary-like objects. Programmers from a Java or C background might be drawn to the compile-time safety checks provided by the typed variables and parameters of Shica and LSL. There is elegance in both languages and their design philosophies, but of quite different kinds, and we feel that a good experience could be enjoyed in both.
Shica seems to be mostly attaining its goals of simplicity while providing adequate scope to allow programmers to economically and elegantly express solutions. States, events, and processes are supported to a degree adequate for our simple tests to date. It also has a familiar syntax and therefore a relatively shallow learning curve for beginners. Resource usage at run-time is low thanks to the compact bytecode representation, small VM, and the use of a small, dedicated GC that works within a fixed-size heap. It can therefore operate in micro-controllers and other resource-limited environments. Automatic memory management increases efficiency and portability while protecting against memory leaks.
On the negative side, Shica could benefit from a macro system. Our experience has been that some repetition of “boilerplate” code would be avoided. No user-defined objects are provided, so structured data is currently not supported and the orthogonal flexibility and control mechanisms made possible by object-oriented state and behavioral sharing are not available.
Global variables must be used for most data transfer between states. This increases dependencies and the risk of unintended modifications, but has the small benefit of making these dependencies explicit.
5.1 State-based programming
Shica supports multiple, concurrent action processing. While a given type of event is processed sequentially, independent events can be processed concurrent.
Code is easier for programmers to write and read because of Shica’s focus on state as the organising principle of the program, as well as the explicit transitions that do not rely on global state variables. In effect, code is modular with each state defining a module boundary which makes program modification easier because there are fewer hidden global dependencies.
Static typing ensures all operations performed by the program are legal, reducing the danger of dynamic type-related errors at runtime. While this is a disadvantage in terms of programming flexibility, we believe embedded and mission-critical systems specifically can gain more from the guarantees that it provides.
Clarity of program behavior is prioritized, and the above benefits come with some costs. Whereas BDI allows small contextual state changes through state variables, in Shica it is difficult to implement these since state is a top-level, global organisational mechanism. States are also not first-class objects; they cannot be duplicated, stored in variables, or passed to/from functions. Currently Shica has no global variables and so state cannot be transferred across state transitions. Perhaps the most serious problem is the lack of internal synchronisation mechanisms for state transitions, meaning that action processing may be interrupted when transitioning between the states.
5.2 Event-driven programming
Shica has no visible event loop. like LSL and JavaScript, Shica events “just work” in a well-defined and predictable manner.
Shica supports flexible event-driven programming with per-event filtering and multiple handlers for a single event, enabling expressive select- and subscribe-like control structures. Events can be duplicated for reusability, and event lifecycle is tied to the current state, providing resource efficiency.
However, Shica currently lacks support for user-defined event triggers and treating variable changes as events. Events are tightly coupled to specific handler functions by the compiler, reducing flexibility. Initialization can cause run-time errors, and all events share the same monitoring frequency, which can lead to inefficiencies in complex systems.
Although concurrency is supported through multiple event handlers, protection of state-local variables from race conditions is not yet implemented, though it would be feasible with some compiler and run-time support.
5.3 Distributed programming
Messages exchanged between Shica nodes are received and handled in the same way as events. Message handing therefore has all the benefits mentioned above for event handling including context-oriented message response based on current state or satisfied conditions in filters, multiple actions for a single received message, concurrent processing of different messages, information sharing between actions using state-local variables.
Shica could be improved in several ways to better support distributed programming both within a single node and between multiple remote nodes. Currently each node runs one Shica program as a single process; there is no way to spawn new processes that run in parallel with independent state management. The messaging mechanism uses broadcast within a group; there is no point-to-point communication and no equivalent to a first-class message channel that could be passed between nodes as a private messaging “capability”.
We would also prefer to follow JavaScript’s lead in unifying behavioral mechanisms. By considering both events and inter-node communication as messages delivered to objects, and their handlers as methods of those objects, a single mechanism would emerge capable of filtering both events and messages based on their parameter types, ranges, or values.
6 Conclusions and future work
In this paper we introduced Shica, an experimental programming language designed to support state-based, event-driven, and distributed computing. The informal evaluation results show that Shica achieves simplicity and flexibility by defining programs based on these three core concepts.
However, Shica remains an evolving language with several limitations. In particular, the lack of user-defined structured data types and the need to use global variables for data sharing between states lead to difficult-to-manage dependencies. The lack of event synchronization mechanisms makes it difficult to ensure consistency of operation. The event initialization and frequency control mechanisms need improvement to prevent resource inefficiencies. Regarding distributed computing, the lack of process control and private communication channels limits scalability and adaptability in dynamic environments.
Future work will focus on addressing these shortcomings by introducing support for structured data, improving event processing mechanisms, and enhancing distributed execution capabilities. We will also investigate a more flexible and general remote event mechanism that can pass more complex information between distributed agents.
In light of our evaluation showing JavaScript to be as economical as Shica, we are also curious to investigate unifying some of Shica’s mechanisms perhaps by adopting a simpler and more dynamic JavaScript-like model of objects and functions, treating state transitions as dynamic changes of type and unifying events, remote messages, and functions into a single behavioral type. It is not clear whether this can be done while keeping resource usage as low as it currently is.
When the language design has stabilized we intend to conduct user trials to judge how well Shica can be applied to real projects, and the extent to which other people find writing Shica programs to be fun or annoying.
We believe that the continued development of Shica will contribute to the design of more intuitive, scalable, elegant, and economic programming paradigms for agent-based and distributed computing systems.
References
- [1] Gul Agha. Actors: a model of concurrent computation in distributed systems. MIT press, 1986.
- [2] Malte Aschermann, Philipp Kraus, and Jörg P Müller. Lightjason: a bdi framework inspired by jason. In European Conference on Multi-Agent Systems, pages 58–66. Springer, 2016. doi:10.1007/978-3-319-59294-7_6.
- [3] Ken Birman and Thomas Joseph. Exploiting virtual synchrony in distributed systems. In Proceedings of the eleventh ACM Symposium on Operating systems principles, pages 123–138, 1987.
- [4] Rafael H Bordini, Jomi Fred Hübner, and Michael Wooldridge. Programming multi-agent systems in AgentSpeak using Jason. John Wiley & Sons, 2007. ISBN 978-0470029008.
- [5] Luca Cardelli. A language with distributed scope. In Proceedings of the 22nd ACM SIGPLAN-SIGACT symposium on Principles of programming languages, pages 286–297, 1995. doi:10.1145/199448.199516.
- [6] Rem W Collier, Seán Russell, and David Lillis. Exploring aop from an oop perspective. In Proceedings of the 5th International Workshop on Programming Based on Actors, Agents, and Decentralized Control, pages 25–36, 2015.
- [7] Tcl/Tk Community. Tcl/tk. Online, 2025. Accessed: 2025-03-18. URL: https://www.tcl-lang.org/.
- [8] Louise A Dennis and Berndt Farwer. Gwendolen: A bdi language for verifiable agents. In Proceedings of the AISB 2008 Symposium on Logic and the Simulation of Interaction and Reasoning, Society for the Study of Artificial Intelligence and Simulation of Behaviour, pages 16–23, 2008.
- [9] Alan AA Donovan and Brian W Kernighan. The Go programming language. Addison-Wesley Professional, 2015.
- [10] Robert Eckstein, Marc Loy, and Dave Wood. Java swing. O’Reilly & Associates, Inc., 1998.
- [11] Arkadeb Ghosal, Thomas A Henzinger, Christoph M Kirsch, and Marco AA Sanvido. Event-driven programming with logical execution times. In International Workshop on Hybrid Systems: Computation and Control, pages 357–371. Springer, 2004.
- [12] Thomas A Henzinger, Benjamin Horowitz, and Christoph M Kirsch. Giotto: A time-triggered language for embedded programming. Proceedings of the IEEE, 91(1):84–99, 2003. doi:10.1109/JPROC.2002.805825.
- [13] Koen V Hindriks, Frank S De Boer, Wiebe Van Der Hoek, and John-Jules Ch Meyer. Agent programming with declarative goals. In Intelligent Agents VII Agent Theories Architectures and Languages: 7th International Workshop, ATAL 2000 Boston, MA, USA, July 7–9, 2000 Proceedings 7, pages 228–243. Springer, 2001. doi:10.1007/3-540-44631-1_16.
- [14] Charles Antony Richard Hoare. Communicating sequential processes. Communications of the ACM, 21(8):666–677, 1978. doi:10.1145/359576.359585.
- [15] Linden Lab. Linden scripting language (lsl) portal. Online, 2025. Accessed: 2025-03-18. URL: https://wiki.secondlife.com/wiki/LSL_Portal.
- [16] Linden Lab. Second life. Online, 2025. Accessed: 2025-03-18. URL: https://secondlife.com.
- [17] Mozilla Developer Network. Javascript, n.d. Accessed: 2025-03-19. URL: https://developer.mozilla.org/en-US/docs/Web/JavaScript.
- [18] OpenSimulator Project. Opensimulator: Open source virtual world server. Online, 2025. Accessed: 2025-03-18. URL: http://opensimulator.org/wiki/Main_Page.
- [19] Anand S Rao. Agentspeak (l): Bdi agents speak out in a logical computable language. In European workshop on modelling autonomous agents in a multi-agent world, pages 42–55. Springer, 1996. doi:10.1007/BFB0031845.
- [20] Anand S Rao and Michael P Georgeff. Modeling rational agents within a bdi-architecture. Readings in agents, pages 317–328, 1997.
- [21] Ripon K Saha, Yingjun Lyu, Hiroaki Yoshida, and Mukul R Prasad. Elixir: Effective object-oriented program repair. In 2017 32nd IEEE/ACM International Conference on Automated Software Engineering (ASE), pages 648–659. IEEE, 2017. doi:10.1109/ASE.2017.8115675.
- [22] Marco A. A. Sanvido, Arkadeb Ghosal, and Thomas A. Henzinger. xgiotto language report. Technical Report UCB/CSD-03-1261, EECS Department, University of California, Berkeley, July 2003. URL: http://www2.eecs.berkeley.edu/Pubs/TechRpts/2003/5457.html.
- [23] Gert Smolka. The oz programming model. Computer Science Today: Recent Trends and Developments, pages 324–343, 2005.
- [24] The Mozart Programming System. Mozart programming system, n.d. Accessed: 2025-03-19. URL: https://mozart2.org/.
- [25] Robert Virding, Claes Wikström, and Mike Williams. Concurrent programming in ERLANG. Prentice Hall International (UK) Ltd., 1996.
Appendix A Radio button group application listings
This appendix presents the listings of the radio button group application in the four languages that we evaluated. Figure 9 shows the Shica implementation, Figure 10 the LSL implementation, Figure 11 the JavaScript implementation, and the Erlang version is shown in Figure 12.
