PicoLisp Explored: Object-Oriented Programming, Part 1
Tags: oop, picolisp, lisp, functional
Published: 2022-01-29 10:22:20

Today we will explore the object-oriented programming possibilities in PicoLisp. 

Despite the crushing judgements of Edsger Dijkstra (*"I don't think object-oriented programming is a structuring paradigm that meets my standards of elegance"*) we will also find some cases where OOP is actually very useful - of course!

So let's be open minded and check out the object oriented concepts of PicoLisp.

-------------------------------

### What is Object Oriented Programming?

[Object-oriented programming](https://en.wikipedia.org/wiki/Object-oriented_programming) is a programming paradigm that centers around the concept of "objects" that can contain data (often called **properties**) and code (often called **methods**). The objects are instances of certain **classes** and inherit their classes' properties and methods.

PicoLisp comes with built-in object oriented extensions. There seems to be a common agreement upon three criteria for object orientation: 

- **Encapsulation:** Code and data are encapsulated into objects, giving them both a behavior and a state. Objects communicate by sending and receiving messages. 
- **Inheritance:** Objects are organized into classes. The behavior of an object is inherited from its class(es) and superclass(es). 
- **Polymorphism:** Objects of different classes may behave differently in response to the same message. For that, classes may define different methods for each message. 

Like all programming paradigms, OOP has cases where it's helpful and others where it's rather producing spaghetti code. We will not discuss the pros and cons here. Let's focus now on how these rather abstract definitions can look like in actual code.

![bonding.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1632763221876/53p7858jx.png)

-------------------------------

### Objects and Classes

*The following information is partially based on the PicoLisp64 OOP-tutorial (PicoLisp64 is the predecessor of pil21). Unfortunately the tutorial is not included in pil21 anymore, therefore I have uploaded the HTML and example files to [Gitlab](https://gitlab.com/picolisp-blog/web-applications/-/tree/main/docs).*

-------------------------------

**Classes** are defined using the ``class`` function. A class
- has a name,
- has method definitions and superclass(es) 
- may have class variables (attributes).

**Objects**
- can be anonymous or [external](https://software-lab.de/doc/ref.html#external),
- have class(es) and optionally method definitions in the value,
- have attributes in their property list.

### Naming conventions

Per convention, class names start with a ``+``, and class methods end with a ``>``. Let's take a look at some examples.

-----------------------------

### A simple base class

Let's take a look at the example from the PicoLisp64 [tutorial](https://gitlab.com/picolisp-blog/web-applications/-/tree/main/docs): A simple base class called ``+Shape`` and two subclasses ``+Rectangle`` and ``+Circle``.

Let's define the class ``+Shape`` using the ``class`` function:

```
(class +Shape)
# x y
```
Per convention, the **class properties should be added as comments** directly after the class function.  As PicoLisp is a dynamic language, a class can be extended at runtime with any number of properties, and there is nothing like a fixed object size or structure. This comment is a hint of **what the programmer thinks to be essential and typical for that class**. In the case of ``+Shape``, ``x`` and ``y`` are the coordinates of the shape's origin. 

Now let's add two method definitions using the function ``dm`` ("define method"). Let's start with the method ``T``, which is a special method: Each time a new object is created, and a method with that name is found in its class hierarchy, that method will be executed.

```
(class +Shape)
# x y

(dm T (X Y)
   (=: x X)
   (=: y Y) )
```
Though ``T`` looks like a "constructor" in other programming languages, it should probably better be called "initializer". The ``T`` method of ``+Shape`` takes two arguments ``X`` and ``Y``, and stores them in the object's property list. 

-------------------------------

Our second method ``move>`` changes the object's origin by adding the offset values ``DX`` and ``DY`` to the object's origin:

```
(dm move> (DX DY)
   (inc (:: x) DX)
   (inc (:: y) DY) )
```
The ``>`` in the method name indicates that it is a method (as opposite to a normal function).

-------------------------------

### Using ``This``

In the examples, we will notice a new variable ``This`` and some new functions: ``:``, ``:=`` and ``::``. What do those stand for?

- ``This``: When we are dealing with objects, we often have the case that we want to refer to the **current object**. In this case, we can use the ``This`` variable.
 
- ``:`` is usually followed by a property and can be read as "Get the **value** for this property from ``This``". 

- ``=:`` can be read as as "**Store a new value** for a property of ``This``".
- ``::`` can be read as  "**Fetch the property cell** of ``This``".

*In other words, ``::`` gets the ``var`` of a cell. This is the same concept like the [``set`` function](https://picolisp-blog.hashnode.dev/picolisp-explored-the-set-function) that we discussed before.*


------------------------

Some examples:

```
   (: x)
```
gets the property ``x``.

```
   (=: x X)
```
sets the value of the object property ``x`` to ``X``, and

```
   (inc (:: x) DX) 
```
gets the value of ``X`` and increases it by the value ``DX``.

-------------------------------

### Subclasses and Inheritance

Now back to our example. Let's create a subclass of ``+Shape`` - our rectangle class ``+Rectangle``. To indicate that ``+Rectangle`` inherits from ``+Shape``, we add the latter one to the ``class`` function:

```
(class +Rectangle +Shape)
# dx dy
```
We see that we have two *new* properties for ``+Rectangle``: ``dx`` and ``dy``. **Additionally**, we also have the ``x`` and ``y`` property that are inherited.

``+Rectangle`` inherits the methods of ``Shape``, for example the ``move>`` function. However, we need to adapt our initializing function ``T`` to the increased properties. We can do that by calling the ``super`` function:

```
(dm T (X Y DX DY)
   (super X Y)
   (=: dx DX)
   (=: dy DY) )
```
This shows that the super class already has a ``T`` method that uses the ``X`` and ``Y`` arguments.

Finally, let's define the methods ``area>``, ``perimeter>`` and ``draw>`` for our ``+Rectangle``.

```
(dm area> ()
   (* (: dx) (: dy)) )

(dm perimeter> ()
   (* 2 (+ (: dx) (: dy))) )

(dm draw> ()
   (drawRect (: x) (: y) (: dx) (: dy)) )
```

--------------------------------

### A second subclass

Let's create a second subclass called ``+Circle``. It also inherits from the superclass ``+Shape`` and has an additional property for the radius, ``r``. Just like for our rectangle class, let's define our ``area>`` and ``draw>`` methods and a new method called ``perimeter>``.

```
(class +Circle +Shape)
# r

(dm T (X Y R)
   (super X Y)
   (=: r R) )

(dm area> ()
   (*/ (: r) (: r) 31415927 10000000) )

(dm perimeter> ()
   (*/ 2 (: r) 31415927 10000000) )

(dm draw> ()
   (drawCircle (: x) (: y) (: r)) )
```

31415927 of course stands for ``pi``. If you are confused why there is no decimal point and don't know the function ``*/``, you will find help in the post about [Fixed Point Arithmetics](https://picolisp-blog.hashnode.dev/floating-point-vs-fixed-point-arithmetics).

-------------------------------

Now we know how to define classes, subclasses, methods and properties. In the next post we will see how to instantiate objects from these and how use them.

You can find the full code for the example [here](https://gitlab.com/picolisp-blog/web-applications/-/blob/main/docs/shape.l).

-------------------------------

### Sources
- https://xkcd.com/1188/  
[PicoLisp64](https://software-lab.de/picoLisp.tgz)  
- https://software-lab.de/doc/ref.html#oop   
- Cover Pic: Circle, Triangle, Rectangle by the Japanese monk [Sengai](https://en.wikipedia.org/wiki/Sengai)