Why Object-Oriented Programming is not the best method to implement Agent-Based Models

By Martin Hinsch

Research Department of Genetics, Evolution and Environment
University College London

Introduction

A considerable part of the history of software engineering consists of attempts to make the complexity of software systems manageable in the sense of making them easier to implement, understand, modify, and extend. An important aspect of this is the separation of concerns (SoC, Dijkstra 1982). SoC reduces complexity by dividing the implementation of a system into (presumably simpler) problems that can be solved without having to spend too much thought on other aspects of the system. Architecturally, SoC is accomplished through modularity and encapsulation. This means that parts of the system that have strong inter-dependencies are put together into a “module” (in the widest sense) that presents only aspects of itself to the outside that are required to interact with other modules. This is based on the fundamental assumption that the visible behaviour of a component (its interface) is simpler than its potentially complex inner workings which can be ignored when interacting with it.

The history of Object-Oriented Programming (OOP) is complicated and there are various flavours and philosophies of OOP (Black 2013). However, one way to see Object Orientation (OO) is as a coherent, formalised method to ensure modularisation and encapsulation. In OOP data and functions to create and manipulate that data are combined in objects. Depending on programming language, some object functions (methods) and properties can be made inaccessible to users of the object, thereby hiding internal complexity and presenting a simplified behaviour to the outside. Many OO languages furthermore allow for polymorphism, i.e. different types of objects can have the same interface (but different internal implementations) and can therefore be used interchangeably.

After its inception in the 1960s (Dahl and Nygaard 1966) OOP gained popularity throughout the 80s and 90s, to the point that many established programming languages were retrofitted with language constructs that enabled OOP (C++, Delphi, OCaml, CLOS, Visual Basic, …) and new languages were designed based on OOP principles (Smalltalk, Python, Ruby, Java, Eiffel,…). By the mid-90s many computer science departments taught OOP not as one, or even just a useful paradigm, but as the paradigm that would make all other methods obsolete.

This is the climate in which agent-based or individual-based modelling (ABM) emerged as a new modelling methodology. In ABM the behaviour of a system is not modelled directly but instead the model consists of (many, similar or identical) individual components. The interactions between these components leads to the emergence of global behaviour.

While the origins of the paradigm reach further back, it only started to become popular in the 90s (Bianchi and Squazzoni 2015). As the method requires programming expertise, which in academia was rare outside of computer science, the majority of early ABMs were created by or with the help of computer scientists, which in turn applied the at the time most popular programming paradigm. At first glance OOP also seems to be an excellent fit for ABM – agents are objects, their state is represented by object variables, and their behaviour by methods. It is therefore no surprise that OOP has become and remained the predominant way to implement ABMs (even after the enthusiasm for OOP has waned to some degree in mainstream computer science).

In the following I will argue that OOP is not only not necessarily the best method to write ABMs, but that it has, in fact, some substantial drawbacks. More specifically, I think that the claim that OOP is uniquely suited for ABM is based on a conceptual confusion that can lead to a number of bad modelling habits. Furthermore the specific requirements of ABM implementations do not mesh well with an OOP approach.

Sidenote: Strictly speaking, for most languages we have to distinguish between objects (the entities holding values) and classes (the types that describe the makeup and functionality of objects). This distinction is irrelevant for the point I am making, therefore I will only talk about objects.

Conceptual confusion

About every introduction to OOP I have come across starts with a simple toy example that demonstrates core principles of the methods. Usually a few classes corresponding to everyday objects from the same category are declared (e.g. animal, cat, dog or vehicle, car, bicycle). These classes have methods that usually correspond to activities of these objects (bark, meow, drive, honk).

Beyond introducing the basic syntax and semantics of the language constructs involved, these introductions also transport a message: OOP is easy and intuitive because OOP objects are just representations of objects from the real world (or the problem domain). OOP is therefore simply the process of translating objects in the problem domain into software objects.

OOP objects are not representations of real-world objects

While this approach makes the concept of OOP more accessible, it is misleading. At its core the motivation behind OOP is the reduction of complexity by rigorous application of some basic tenets of software engineering (see Introduction). OOP objects therefore are not primarily defined by their representational relationship to real-world objects, but by their functionality as modules in a complicated machine.

For programmers, this initial misunderstanding is harmless as they will undergo continued training. For nascent modellers without computer science background, however, these simple explanations often remain the extent of their exposure to software engineering principles, and the misunderstanding sticks. This is unfortunately further reinforced by many ABM tutorials. Similar to introductions to OOP they present the process of the implementation of an ABM as simply consisting of defining agents as objects, with object properties that represent the real-world entities’ state and methods that implement their behaviour.

At this point a second misunderstanding almost automatically follows. By emphasising a direct correspondence between real-world entities and OOP objects, it is often implied (and sometimes explicitly stated) that modelling is, in fact, the process of translating from one to the other.

OOP is not modelling

As mentioned above, this is a misinterpretation of the intent behind OOP – to reduce software complexity. Beyond that, however, it is also a misunderstanding of the process of modelling. Unfortunately, it connects very well with a common “lay theory of modelling” that I have encountered many times when talking to domain experts with no or little experience with modelling: the idea that a model is a representation of a real system where a “better” or “more correct” representation is a better model.

Models are not (simply) representations

There are various ways to use a model and reasons to do it (Epstein 2008), but put in the most general terms, a (simulation) model is an artificial (software) system that in one way or other teaches us something about a real system that is similar in some aspects (Noble 1997). Importantly, however, the question or purpose for which the model was built determines which aspects of the real system will be part of the model. As a corollary, even given the same real-world system, two models with different questions can look very different, to the point that they use different modelling paradigms (Hinsch and Bijak 2021).

Experienced modellers are aware of all this, of course, and will not be confused by objects and methods. For novices and domain experts without that experience, however, OOP and the way it is taught in connection with ABM can lead to a particular style of modelling where first, all entities in the system are captured as agents, and second, these agents are being equipped with more and more properties and methods, “because it is more realistic”. 

An additional issue with this is that it puts the focus of the modelling process on entities. The direct correspondence between nouns in our (natural language-based) description of the model and classes in our object-oriented implementation makes it very tempting to think about the model solely in terms of entities and their properties.

ABMs are not (just) collections of entities

There are other reasons to build a simulation model, but in most cases the dynamic behaviour of the finished model will be crucial. The reason to use an ABM as opposed to, say, a differential equation model, is not that the system is composed of entities, but that the behaviour of the system depends in such a way on interactions between entities that it cannot be reduced to aggregate population behaviour. The “interesting” part of the model is therefore not the agents per se, but their behaviour and the interactions between them. It is only possible to understand the model’s macroscopic behaviour (which is often the goal of ABM) by thinking about it in terms of microscopic interactions. When creating the model it is therefore crucial to think not (only) about which entities are part of the system, but primarily which entity-level interactions and behaviours are likely to affect the macroscopic behaviour of interest.

To summarise the first part, OOP is a software engineering methodology, not a way to create models. This unfortunately often gets lost in the way it is commonly taught (in particular in connection with ABM), so that OOP can easily lead to a mindset that sees models as representations, emphasises “realism”, and puts the focus on entities rather than the more important interactions.

Practical considerations

But assuming a seasoned modeller who understands all this – surely there would be no harm in choosing an OOP implementation?

At first approximation this is certainly true. The points discussed above apply to the modelling process, so assuming all of the mentioned pitfalls are avoided, the implementation should only be a matter of translating a formal structure into working program code. As long as the code is exactly functionally equivalent to the formal model, it should not matter which programming paradigm is used.

In reality things are a little bit more complicated, however. For a number of reasons model code has different properties and requirements to “normal” code. These combine to make OOP not very suitable for the implementation of ABMs.

OOP does not reduce complexity of an ABM

Any non-trivial piece of software is too complicated to understand all at once. At the same time, we usually want its behaviour to be well-defined, well-understood, and predictable. OOP is a way to accomplish this by partitioning the complexity into manageable pieces. By composing the program of simple(r) modules, which in turn have well-defined, well-understood, and predictable behaviour and which interact in a simple, predictable manner, the complexity of the system remains manageable and understandable.

An ABM has parts that we want to be well-understood and predictable as well, such as parameterisation, data output, visualisation, etc. For these “technical” parts of the simulation program, the usual rules of software engineering apply, and OOP can be a helpful technique. The “semantic” part, i.e. the implementation of the model itself is different, however. By definition, the behaviour of a model is unpredictable and difficult to understand. Furthermore, in an ABM the complexity of the model behaviour is the result of the (non-linear) interactions between its components – the agents – which themselves are often relatively simple. The benefit of OOP – a reduction in complexity by hiding it behind simple object interfaces – therefore does not apply for the semantic part of the implementation of an ABM.

OOP makes ABMs more difficult to read and understand

There is more, however. Making code easy to read and understand is an important part of good practice in programming. This holds even more so for ABM code.

First, most ordinary application code is constructed to produce very specific runtime behaviour. To put it very simply – if the program does not show that behaviour, we have found an error; if it does, our program is by definition correct. For ABM code the behaviour can not be known in advance (otherwise we would not need to simulate). Some of it can be tested by running edge cases with known behaviour, but to a large degree making sure that the simulation program is implemented correctly has to rely on inspection of the source code.

Second, for more complicated models such as ABMs the simulation program is very rarely just the translation of a formal specification. Language is inherently ambiguous and to my knowledge there is no practical mathematical notation for ABMs (or software in general). Given further factors such as turnaround times of scientific work, ambiguity of language and documentation drift, it is often unavoidable that the code remains the ultimate authority on what the model does. In fact, good arguments have been made to embrace this reality and its potential benefits (Meisser 2016), but even so we have to live with the reality that for most ABMs, most of the time, the code is the model.

Finally, an important part of the modelling process is working out the mechanisms that lead to the observed behaviour. This involves trying to relate the observed model behaviour to the effect of agent interactions, often by modifying parameter values or making small changes to the model itself. During this process, being able to understand at a glance what a particular piece of the model does can be very helpful.

For all of these reasons, readability and clarity are paramount for ABM code. Implementing the model in an OO manner directly contradicts this requirement. We would try to implement most functionality as methods of an object. The processes that make up the dynamic behaviour of the model – the interactions between the agents – are then split into methods belonging to various objects. Someone who tries to understand – or modify – a particular aspect of the behaviour then has to jump between these methods, often distributed over different files, having to assemble the interactions that actually take place in their mind. Furthermore, encapsulation, i.e. the hiding of complexity behind simple interfaces, can make ABM code more difficult to understand by giving the misleading impression of simplicity. If we encounter agent.get_income() for example, we might access a simple state variable or we might get the result of a complex calculation. For normal code this would not make a difference since the potential complexity hidden behind that function call should not affect the caller. For ABM code, however, the difference might be crucial.

To sum up the second part – due to the way complexity arises in ABMs an OOP implementation does not lead to simplification, but on the contrary can make the code more difficult to understand and maintain.

Conclusion and discussion

Obviously none of the points mentioned above are absolutes and excellent models have been created using object-oriented languages and implementation principles. However, I would like to argue that the current state of affairs where object-orientation is uncritically presented as the best or even only way to implement agent-based models does on average lead to worse models and worse model implementations. I think that in the future any beginner’s course on agent-based modelling should at least:

  • Clarify the difference between model and implementation.
  • Show examples of the same model implemented according to a number of different paradigms.
  • Emphasise that ABMs are about interactions, not entities.

Concerning best practices for implementation, I think readability is the best guideline. Personally, I have found it useful to implement agents as “shallow” objects with the rule of thumb that only functions that a) have an obvious meaning and b) only affect the agent in question become methods implemented at the same place as the agent definition. Everything else is implemented as free functions, which can then be sorted into files by processes, e.g. ’reproduction’ or ’movement’. This avoids philosophical problems – does infection in a disease model, for example, belong to the agents, some environment object or maybe even a disease object? But above all it makes it easy to quickly find and understand a specific aspect of the model.

If at the same time the model code is kept as independent of the parts of the code that manages technical infrastructure (such as parameter loading or gui) as possible, we can maintain the implementation of the model (and only the model) as a self-contained entity in a form that is optimised for clarity and readability.

References

Bianchi, Federico, and Flaminio Squazzoni. 2015. “Agent-Based Models in Sociology.” Wiley Interdisciplinary Reviews: Computational Statistics 7 (4): 284–306. https://doi.org/10.1002/wics.1356.

Black, Andrew P. 2013. “Object-Oriented Programming: Some History, and Challenges for the Next Fifty Years.” Information and Computation, Fundamentals of Computation Theory, 231 (October): 3–20. https://doi.org/10.1016/j.ic.2013.08.002.

Dahl, Ole-Johan, and Kristen Nygaard. 1966. “SIMULA: An ALGOL-Based Simulation Language.” Commun. ACM 9 (9): 671–78. https://doi.org/10.1145/365813.365819.

Dijkstra, Edsger W. 1982. “On the Role of Scientific Thought.” In Selected Writings on Computing: A Personal Perspective, edited by Edsger W. Dijkstra, 60–66. New York, NY: Springer. https://doi.org/10.1007/978-1-4612-5695-3_12.

Epstein, Joshua M. 2008. “Why Model?” Jasss-the Journal of Artificial Societies and Social Simulation 11 (4): 12. https://doi.org/10.13140/2.1.5032.9927.

Hinsch, Martin, and Jakub Bijak. 2021. “Principles and State of the Art of Agent-Based Migration Modelling.” In Towards Bayesian Model-Based Demography: Agency, Complexity and Uncertainty in Migration Studies. Methodos Series 17, 33-49.

Meisser, Luzius. 2016. “The Code Is the Model.” International Journal of Microsimulation 10 (3): 184–201. https://doi.org/10.34196/ijm.00169.

Noble, Jason. 1997. “The Scientific Status of Artificial Life.” In Poster Presented at the Fourth European Conference on Artificial Life (ECAL97), Brighton, UK.

Hinsch, M.(2025) Why Object-Oriented Programming is not the best method to implement Agent-Based models. Review of Artificial Societies and Social Simulation, 3 Feb 2026. https://rofasss.org/2026/02/03/oop


© The authors under the Creative Commons’ Attribution-NoDerivs (CC BY-ND) Licence (v4.0)

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.