Codemes

Biological Evolution vs Evolution of
Programming Languages

Who am I?

Frank Hellenkamp
Freelance Web Developer
Designer
Physics (and Science) Enthusiast

But: Let's start with…

Darwin

Charles Darwin

Darwin

Darwinian Evolution

Darwinian Evolution

Evolution is the change in the heritable characteristics of biological populations over successive generations.

It occurs when evolutionary processes such as natural selection and genetic drift act on genetic variation, resulting in certain characteristics becoming more or less common within a population over successive generations.

Wikipedia

The funny thing is…

Charles Darwin never new about DNA.
(A concept that is very familiar to us today.)
He lived from 1809 to 1882.

But it was Watson and Crick who discovered the concrete structure of DNA in 1953, which is 71 years after his death.

DNA as information carrier

That there has to be something like genes (an information carrier for self-replication) were proposed by Schrödinger in his book What is life? in 1944.

And much more sopisticated account of self-replication of information was written by John von Neumann in his book Theory of Self-Reproducing Automata in 1966.

The Selfish Gene

In 1976 Richard Dawkins proposed the idea, that evolution does not act on individuals, but on genes.

Genes are the units of selection, and they are selfish. They are only interested in their own survival and reproduction.

But genes (as information carriers) are

CODE

Code Evolution

Brainfuck?

Brainfuck is an esoteric programming language created in 1993 by Urban Müller, and is notable for its extreme minimalism. The language consists of only eight simple commands and an instruction pointer.

And it is fully Turing complete.

Brainfuck

What are the commands?


            < head0 = head0 - 1
            > head0 = head0 + 1
            { head1 = head1 - 1
            } head1 = head1 + 1
            - tape[head0] = tape[head0] - 1
            + tape[head0] = tape[head0] + 1
            . tape[head1] = tape[head0]
            , tape[head0] = tape[head1]
            [ if (tape[head0] == 0): jump forwards to matching ] command.
            ] if (tape[head0] != 0): jump backwards to matching [ command.
        

Brainfuck

What would a program look like?


>>>++[
    <++++++++[
        <[<++>-]>>[>>]+>>+[
            -[->>+<<<[<[<<]<+>]>[>[>>]]]
            <[>>[-]]>[>[-<<]>[<+<]]+<<
        ]<[>+<-]>>-
    ]<.[-]>>
]
"Random" byte generator using the Rule 30 automaton.
Doesn't terminate; you will have to kill it.
To get x bytes you need 32x+4 cells.
Daniel B Cristofani (cristofdathevanetdotcom)
http://www.hevanet.com/cristofd/brainfuck/
        

Evolution in Brainfuck

Now for the interesting part.

There is a paper by Blaise Agüera y Arcas called:

Computational Life: How Well-formed, Self-replicating Programs Emerge from Simple Interaction

It is about the evolution of emerging self replicators in Brainfuck.

A part of the 2D BFF soup in the process of state transition. Every 8x8 pixel square represents a single tape. Tapes are arranged in a 2d array and interactions only happen within a radius 2 neighbourhood of every cell. The small pre-transition area of the soup at bottom of the figure is being gradually overtaken by the wave of self-replicators.
Ecosystem of self-replicators on a 2D grid. First the wave of stack based self-replicators sweeps the grid and forms an “ecosystem” of a few co-existing variants. Then the grid is overtaken by more robust self-replicators that use memory copy instructions.

Replicators are taking over and are becoming more complex

Visualization of a 2d Forth primordial soup, in order from left to right: before state transition, at the start of it, just after the majority of programs has become a self-replicator, and many evolution steps afterwards. https://www.youtube.com/watch?v=eOHGBuZCswA

When I heard about this for the first time, I was

MINDBLOWN

But Frank, that's interesting and all…

What does it have to do

with us?

Let's go back to
The Selfish Gene

Richard Dawkins not only talked about genes.

He propsed the idea, that not only genes can replicate, but also ideas.

And for that, he coined a new term, that you all know.

MEME

MEME

A meme is an idea, behavior, or style that spreads from person to person within a culture, often through imitation, and can take various forms such as images, videos, or phrases.

Encyclopedia Britannica

To close the circle

I want to propose a new term

CODEME

A codeme is an coding idea, structure, or style that spreads from person to person within a developer community.

It can spread in one programming language but also across different languages.

Codemes live and evolve in the shared environment of our code, our computers, and our brains.

Frank Hellenkamp

Codemes

Evolution in Programming Languages

Using the example of the Javascript Ecosystem.

Why is the javascript ecosystem so interesting?

  • I think it is currently the fastest moving ecosystem
  • The javascript language is very extensible (polyfills)
  • Long history of being "open"
  • Multiple competing implementations
  • A mix of developers from many different contexts

Javascript Package Managers

Javascript Frontend Frameworks

Why is biological evolution so robust?

Natural selection may explain the survival of the fittest, but it cannot explain the arrival of the fittest.

What Andreas Wagner and his team showed, is that there are many neighboring paths that lead to similar solutions. That is one of the reasons why evolution can explore such a big space of possibilities.

You can have many different genotypes that lead to a similar phenotype.

Why is code evolution getting more rubust?

We also know this phenomenon from code:

There are many different algorithms to implement the same functionality.

(A very common example would be sorting algorithms.)

Another example: Loops


                    const el = [1, 2, 3, 4, 5];
                    var i = 0;

                    while (i < el.length) {
                        element = el[i];
                        console.log(element);

                        i++;
                    }
                

                    const el = [1, 2, 3, 4, 5];

                    for (var i = 0; i < el.length; i++) {
                        element = el[i];
                        console.log(element);
                    }
                

                    const el = [1, 2, 3, 4, 5];

                    for (const element of el) {
                        console.log(element);
                    }
                

                    const el = [1, 2, 3, 4, 5];

                    el.forEach(function(element) {
                        console.log(element);
                    });
                

                    const el = [1, 2, 3, 4, 5];

                    el.forEach((element) => {
                        console.log(element)
                    });
                

                    const el = [1, 2, 3, 4, 5];

                    const changed = el.map(
                        (element) => element * 2
                    );
                

Another example: Conditionals


                    function (expr) {
                      switch (expr) {
                        case 'Oranges':
                          // action for oranges
                          break;
                        case 'Mangoes':
                        case 'Papayas':
                          // action for mangoes
                          // and papayas
                          break;
                        default:
                          // default action
                      }
                    }
                

                    function (expr) {
                      if (expr === 'Oranges') {
                        // action for oranges
                      } else if (
                        expr === 'Mangoes' ||
                        expr === 'Papayas'
                      ) {
                        // action for mangoes
                        // and papayas
                      } else {
                        // default action
                      }
                    }
                

Another example: Conditionals

What I prefer – RETURN EARLY


                function (expr) {
                  if (expr === 'Oranges') {
                    // action for oranges
                    return result1;
                  }

                  if (['Mangoes', 'Papayas'].includes(expr)) {
                    // action for mangoes
                    // and papayas
                    return result1;
                  }

                  // default action
                  return result3;
                }
            

Why is code evolution getting more rubust?

Another reason, is the tools we have.

One important example would be GIT.

Some of the language used, even resembles language used in biology:

CLONING
FORKING
MERGING
BRANCHES

Charles Darwin's Tree of Life

Thank you!

Coding Club

Questions? Comments? Feedback?