This hidden maze is stateful. With the correct sequence of actions, the marble will find the exit, but skip one action, and all is lost. This is because the position of the marble -the state of the maze- influences the result of any action.

### Introduction

The term StateFul/StateLess is often used in communication protocols and comes from functionnal programming. We will focus here on a tiny aspect of this term, limited to the code we create in our humble scientific software craftsmanship.

A Stateful code implies that the developer using this code must pay a significant attention to some implicit information, which we will call a “state”. Oppositely, the code is stateless if it is presented in a way the developer can forget about a state. Fighting for a stateless programming interface is worth your attention, and here is why…

### Making a Turtle state-less

In the famous coding game turtle, kids learn programming by giving a list of instructions to a “turtle” moving on a canvas. There is an online turtle you can use to try these examples. For example, the following code here draws a square

```# Draw a square
# numbers are the successive positions of the turtle
#        3┌──────┐2
#         │      │
#         │      │
#         │      │
#      0,4x──────┘1
t = turtle.Turtle('turtle')
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
turtle.done()
```

This coding game requires the Theory of mind, in other words the capacity to understand other entities by ascribing mental states to them. The mental states of the turtle are both its position (points 0,1,2,3 &4) and direction (resp. east, north, west, south).

Switch two instructions and the output of the game is totally wrong:

```# Draw a square - mistaken
# numbers are the successive positions of the turtle
#  3       0,2      1
#  ┌────────────────
#  │
#  │
#  │
#  x 4
t = turtle.Turtle('turtle')
t.forward(100)     #
t.left(90)         #
t.left(90)         #
t.forward(100)     # swapping these calls changes output
t.forward(100)     #
t.left(90)         #
t.forward(100)     #
t.left(90)         #
turtle.done()
```

This is a typical drawback of a stateful programing.

However, you can draw the square segments in an almost stateless fashion like this:

```# Draw a square, stateless
# numbers are the successive positions of the turtle
#      2,4┌──────┐1,7
#         │      │
#         │      │
#         │      │
#    0,3,6└──────┘5,8

t = turtle.Turtle('turtle')
t.penup()

def draw_segment(t,x0,y0,x1,y1):
t.goto(x0,y0)
t.pendown()
t.goto(x1,y1)
t.penup()

draw_segment(t,0,100, 100,100)#
draw_segment(t,0,0, 0,100)    # swapping these calls are allowed
draw_segment(t,100,0, 0,0)    #
draw_segment(t,100,100, 100,0)#

turtle.done()
```

With this version, one can draw segments with the turtle without anticipating the state, be it position or orientation. It is therefore easier to extend. For example imagine how you would add two diagonals to the square with the initial, stateful version? And with the stateless one?

### Stateless code is easier to read : the Pressure computation

We move to a more applied case to show the effect of a stateless code on readability.

Assume someone want compute Pressure (`P`) from temperature (`T`) and Density (`Rho`) with the ideal gas law.

```state = [T, Rho]
print(state)
>> 300, 1.26
ideal_gas_law(state)
print(state)
>>  300, 1.26, 101325
print("pressure :", state[2])
>> pressure :101325
```

The function `ideal_gas_law()` is changing the `state` data, by adding a pressure to the list of state variables. The variable `state` must be kept in mind, since even its shape is changing in this dataflow. In particular : 1. it is not obvious to guess where pressure was computed. 1. `ideal_gas_law()` would probably fail if it was called a second time, or worse, work with wrong inputs. 1. the last print, done before the call of `ideal_gas_law()`, would raise a cryptic “IndexError”.

To make it stateless, we keep the shape of the variable `state` unchanged. `pressure` is a additional function `ideal_gas_law2()` which ignores the variable `state` and ask separately temperature and density.

```state = [T, Rho]
print(state)
>> 300, 1.26
press = ideal_gas_law2(temp=state[0], rho=state[1])
print(state)
>>  300, 1.26
print("pressure :", press)
>> pressure :101325
```

This fixes our issues:

1. The computation of the `press` variable is easy to spot.
2. `ideal_gas_law2()` can be called multiple times.
3. the last print, done before the call of `ideal_gas_law()`, would raise a clear `variable press is not defined` .

In other words, the data flow - the way the data is edited in the code - is easier to understand.

### Spot the smell of a stateful development : A FORTRAN example

Imagine we are creating a FORTRAN feature able to concatenate strings, for example `pif` added to `paf` yields `pifpaf`.

```program StringConcatenation
implicit none

character(len=10) :: string1 = "pif", string2 = "paf"

! Call the subroutine to concatenate the strings
call concatenateStrings(string1, string2)

! Print the concatenated result
write(*,*) "Concatenated String: ", trim(string1)

contains

subroutine concatenateStrings(str1, str2)
character(len=*), intent(inout) :: str1
character(len=*), intent(in) :: str2

! Concatenate the strings
str1 = trim(str1) // trim(str2)
end subroutine concatenateStrings

end program StringConcatenation
```

This works, but is quite fragile. Indeed, the subroutine will work as expected only if there are less non-blanks characters of `str2` than blanks characters at the end of `str1`:

`str1` (len) `str2` (len) result (len)
`"paf "`(10) `"pif "`(10) `"pafpif "`(10)
`"paf "`(10) `"pif_000000"`(10) `"pafpif_000"`(10)
`"paf_000000"`(10) `"pif_000000"`(10) `"paf_000000"`(10)

As the size of `str1` is set at the input and not changed, it will impact the output. This is because `str1` is both the input and the output of `concatenateStrings()` (intent INOUT). It is a stateful data.

At this point one could start a clever development with a `str1` reallocated in the routine to change its lenght, plus maybe a clever way to tell the main `StringConcatenation` program that `str1` changed… or switch to a stateless version:

```program StringConcatenation
implicit none

character(len=10) :: resultString
character(len=3) :: string1 = "pif", string2 = "paf"

! Call the subroutine to concatenate the strings
call concatenateStrings(string1, string2, resultString)

! Print the concatenated result
write(*,*) "Concatenated String: ", trim(resultString)

contains

subroutine concatenateStrings(str1, str2, result)
character(len=*), intent(in) :: str1, str2
character(len=*), intent(out) :: result

! Concatenate the strings
result = trim(str1) // trim(str2)
end subroutine concatenateStrings

end program StringConcatenation
```

With this stateless version, both input and output are separatelty set in the main program, and the surbroutine just takes in whatever size is set.

The new code is not able to auto-adapt to all situations, but surprises are easier to spot and correct from the main program:

`str1` (len) `str2` (len) result (len)
`"paf"`(3) `"pif"`(3) `"pafpif "`(10)
`"paf"`(3) `"pif_000000"`(3) `"pafpif "`(10)
`"paf"`(3) `"pif_000000"`(10) `"pafpif_000"`(10)
`"paf"`(3) `"pif_000000"`(10) `"pafpif_000000"`(13)

Next time you are using an INOUT parameter in Fortran, do consider spliting it into separate inputs and outputs: it could be closer to your expectation than you think at first!

### How far a code should be stateless?

Stateless is not a silver bullet to remove dirty code, so do not overdo it : it could backfire.

To our experience up to now, it is good practice to push the low-level code of a project towards stateless-ness. The low-level features tend to be moved around a lot. More over, their inputs/outputs tend to be smaller, more atomic , in short good candidates for functionnal programming.

On the other hand, high level code -the central components that makes the main calls- shows little advantage to be moved to a stateless version it self. For example a CFD solver is all about updating the state of the flow along the time. Making it stateless is counter intuitive.

In a nutshell, try to add some stateless-ness in the lower parts of the code, and watch for the gains in readability. If it prove to be too hard, focus more on a potential design problem, than blindly force statefulness.

### Can everything be stateless?

No, some situations are stateful by nature. Here are the most common we deal with:

• writing an input file on a disk. However you can generate the content in memory in a stateless manner, only the final I/O is stateful.
• interacting with a stateful service, for example a job scheduler on an HPC machine.
• event driven situations like a Graphical User Interface.

However, remember that most of the littles actions around these situations can be separated in neat little stateless bricks.