Factor pt. 3 - Tuple classes
Tags: factor, esoteric, oop, tutorial
Published: 2021-10-11 12:40:30

From my previous tutorials you should already know how to operate with values on the stack and use sequences and combinators to make control structures. Data types paid a crucial role in both of these articles and are very important all over Factor. Today I will explain how Factor class system works based on tuple classes.

### Object oriented programming
###### What I know about it
As far as I know OOP has been the most popular programming paradigm for some time. It's sometimes presented in opposition to Functional Programming, but although both of them are called "paradigms" they touch very different aspects of programming and can easily coexist. Factor manages to be both an object oriented and a concatenative language.

In OOP programs are based on the concept of "objects" that contain data (called fields) and code (called methods). These objects interact with each other and create new objects to perform required tasks. In most languages, including Factor, each object is an instance of a class which tells us its type, what data it holds and what we can do with it. For example `1` is an instance of an integer class. It represents a number and arithmetic operations can be performed on it. `[ dup * ]` is an instance of quotation. It holds a snippet of code and can be passed as an argument to combinators.

The thing that makes OOP so useful is that a program may define new classes with their own fields and methods. In Factor this is done using class tuples.

### Defining a class
###### Just fields for now
Just as with most definitions in Factor a syntax word is used to create new tuple classes: `TUPLE:`. It's syntax is:
```Factor
TUPLE: class-name slots... ;
```
Slots define fields of a class and can take one of the following forms:
 - `name` - A slot that can hold any object
 - `{ name attributes... }` - A slot that can hold any object with optional attributes
 - `{ name class attributes... }` - A slot that can hold an instance of the class with optional attributes

All this can sound very confusing, so let's look at an example. Let's define a class for books. Let's say each book shall hold information about it's title, author, genre, and how many times it has been borrowed. A tuple class for such books would be defined like that:
```Factor
TUPLE: book
    { title string read-only }
    { author string read-only }
    { genre string read-only }
    { times-borrowed integer initial: 0 }
;
```
Each slot of this tuple can only store a particular type of data. It may seem like an unnecessary restriction, but it makes code more readable and can prevent some mistakes later on in the program. Three slots have a `read-only` attribute which means once they are set they can't be changed. The last slot has an `initial:` attribute which specifies what value it should have at the start

### Instantiating classes
###### Making actual objects holding data
There are two basic constructor words in Factor that let you create class instances. The simpler one, `new ( class -- tuple )`, only takes a class as an argument and creates a new tuple with default slot values. Continuing the book example this is how to create a default book:
```Factor
book new
! S: T{ book f "" "" "" 0 }
```
This book's prettyprint shows three empty strings and a zero respectively. To actually insert some information into that book we need to use the other constructor: `boa ( slots... class -- tuple )`. In addition to a class it requires values to be put into the slots **b**y **o**rder of **a**rguments - hence the name. For example to describe the toki pona dictionary one would write:
```Factor
"Toki Pona Dictionary" "Sonja Lang" "Dictionary" 1 book boa
! S: T{ book f "Toki Pona Dictionary" "Sonja Lang" "Dictionary" 1 }
```
This time you can see contents of each of the slots initialised to a proper value. Disregard the `f` between the class name and the title: it's just a quirk of Factor literal tuple syntax. For more info visit `\ T{ help`.

### Getters and setters
###### Working with objects
It is useful to change values of slots of a tuple after we created it. In our example that would be incrementing the `times-borrowed` slot whenever someone borrows a book. It would also be nice to extract values from the object to use in the program, that's what they are there for after all. To facilitate that each class in factor comes with a set of getter and setter words.

*Getters* extract values of slots from an object. They are defined automatically based on object's slot names. They consume the object and return the value of a corresponding slot.
```Factor
slot-name>> ( object -- value )
```
For example to get a book's title you would use a word `title>>`.

*Setters* (as the name suggests) set a slot to a given value. They are also defined by the system for each class but only for writeable slots: those without the `read-only` attribute. They consume an object and a value and return the same object.
```Factor
>>slot-name ( object value -- object )
```
The only writeable slot in our example is `times-borrowed`, and its setter is `>>times-borrowed`.

Setters are actually a wrapper over *writers*: lower level words that consume a value and an object and return nothing. They aren't commonly used in programs because it's usually more convenient to keep the object on the stack.
```Factor
slot-name<< ( value object -- )
```

There is one more group of accessor words: *changers*. They take a quotation and an object and apply the quotation to the slot updating it.
```Factor
change-slot-name ( object quot -- object )
```
A `change-times-borrowed` changer will be very useful to update the counter whenever a book is borrowed.

It is important to remember that most of the time if an object is copied (for example by `dup`) it is actually still the same object existing on the stack twice. If its slots are changed they are changed for all copies. This is called a "shallow copy" and it is common among high level languages. For those of you familiar with C++ it's comparable to copying a pointer.

### Constructors
###### How to actually instantiate the class
Using only `new` and `boa` can get tedious, especially if data needs some processing before being put into slots or if you need some slots to have default initial values. In the book example whenever I get a new book it's `times-borrowed` value is always 0. Based on the premise that every time some code is about to be repeated it should be factored out I should write a better constructing word for my book class.

By convention constructors that create an instance of a class are called `<class-name>`. I want my constructor to have a stack effect of `( title author genre -- book )`. A constructor word can be defined using `new` or `boa`, but in our case `new` is not useful: it will set read-only slots to their default values before my defined constructor can affect them. In this case a constructor using `boa` is quite simple: it only needs to add a default 0 and the class.
```Factor
: <book> ( title author genre -- book )
    0 book boa
;
```

There is another constructor naming convention used in Factor: `new-class-name`. These constructors, apart from usual arguments, also take a class as an argument. They are mostly useful when subclassing which is out of scope of this tutorial so I won't be presenting an example.

### Defining methods
###### How to make the same word do different things
Usefulness of methods in OOP comes from the fact that you don't need to know anything about the object except that it implements a particular method to use that method. For example if a program is to do something based on length of an object it can call a `length` word on it, not matter if it's an array, a quotation, a linked list or a vector. Calculating length works differently for each of these classes, but it is always invoked by the same name.

Usually this is implemented using the dot operator: `class.method()`. In Factor however there are no operators, only words. Instead of the dot operator Factor allows to define *generic words*: words that first check what type are their arguments and execute different functions associated with that type. I've already shown examples of generic words: all accessors are generic and they will work on any object that has slots of a certain name.

A generic words are declared with syntax words `GENERIC:` and `GENERIC#:`. The first one creates words that check the type of the top value on the stack. The other allows to specify which value to check. Their syntax is:
```Factor
GENERIC: word ( stack -- effect )
GENERIC#: word n ( stack -- effect )
```
Notice that generic words have their stack effects defined at declaration. Each method connected to the same generic word must have the same stack effect. What is not declared is the body of the generic word. There will be multiple bodies defined for each class separately.

To attach a method to a generic word we need a syntax word `M:` with syntax:
```Factor
M: class generic definition... ;
```
Stack effect of the word were declared with the word itself. This only serves to attach a method to a word and a class.

As an example let's define a method that would be called whenever someone borrows a book. It needs to take a book as input, increase its `times-borrowed` by one and not return anything. It's declaration and definition will look like:
```Factor
GENERIC: borrow ( object -- )

M: book borrow
    [ 1 + ] change-times-borrowed drop
;
```
For now `borrow` only has effect on `book` objects, but it could be implemented for other classes in ways that make sense for these classes.

### Conclusion
###### The tip of the iceberg
What I explained barely scratches the surface of what Factor can do with classes. It is heavily based on them and even though you can do without this knowledge you will be using classes without knowing. This article hopefully shown you enough that you will be able to noticed Object Oriented features and start using them in your own programs. Next time I will be explaining vocabularies.