a blog about things that I've been thinking hard about

AganeAndAgane – Supporting Repetitionism in the Enterprise

20 August, 2006
different repetition bad, exact repetition good

DRY = Don't Repeat Yourself.

But, repetition is most harmful when the repetition is inexact.

DRYDBERIOK = Don't Repeat Yourself Differently But Exact Repetition Is OK.
DRYDBERIOK = Don't Repeat Yourself Differently But Exact Repetition Is OK.

AganeAndAgane is a programming language that supports exact repetitionism.
AganeAndAgane is a programming language that supports exact repetitionism.
AganeAndAgane is a programming language that supports exact repetitionism.

DRY vs DRYDBERIOK

The prophets of Pragmatic Programmerism extol the virtues of "DRY", i.e. "Don't Repeat Yourself". But anyone who has programmed in the enterprise knows that perfect non-repetitionism is often unattainable. For example, an Enterprise Application typically has a Client-Side and a Server-Side, and there is usually going to be repetition across these two components. Add in n-tier stacks, databases, and scalable multi-server solutions, and repetition is all but inevitable.

The AganeAndAgane programming language is a high-level dynamic strongly-typed almost-functional programming language that borrows ideas from Java, Python and Ruby. It is based on an alternative philosophy of "DRYDBERIOK", or "Don't Repeat Yourself Differently, But Exact Repetition Is OK".

To explain the motivation behind this philosophy, consider the following Java class definition:

public class Person {

  private String name;

  public String getName() {
    return name;
  }

  public void setName (String name) {
    this.name = name;
  }
}

This code defines a class Person with a single attribute name of type String. Notice that the word "name" is repeated seven times, and the word "String" is repeated three times. Furthermore, notice that each repetition of these words appears in a different context. For practitioners of DRYDBERIOK, this is a warning sign, or code smell: the appearance of repeated source code which is repeated differently.

Now look at the following equivalent class definition in the AganeAndAgane programming language:

class Person:

  name: String;
  name: String;
  name: String;
  name: String;
  name: String;
  name: String;
  name: String;
  name: String;

As in the Java code, there is repetition. Each of the words "name" and "String" appears eight times. But the important difference is that each repetition is the same.

The repetition-invariant semantics of AganeAndAgane is not limited to attribute definitions. For example, here is some code that shows repeated class and method definitions:

class Person:

  name: String;
  name: String;
  birthday: Date;
  birthday: Date;
  birthday: Date;

  def age:
    return Today() - birthday;

class Person:
  name: String;
  birthday: Date;
  birthday: Date;
  birthday: Date;

  def age:
    return Today() - birthday;
  def age:
    return Today() - birthday;
  def age:
    return Today() - birthday;

class Person:
  name: String;
  name: String;
  birthday: Date;

  def age:
    return Today() - birthday;

An important feature of the AganeAndAgane development environment is the detection of non-exact repetitions. For example, the following class definition contains some incorrectly different repeated definitions of the attribute "name":

class Person:
  name: String;
  name: String;
  name: String;
  name: char[];
  name: char[];

The first three definitions define it to be of type "String" whereas the second two define it to be of type "char[]". The AganeAndAgane compiler will report this as an error:

person.aaa:2:"name" defined as String but defined as char[] on line 5
person.aaa:2:"name" defined as String but defined as char[] on line 6
person.aaa:3:"name" defined as String but defined as char[] on line 5
person.aaa:3:"name" defined as String but defined as char[] on line 6
person.aaa:4:"name" defined as String but defined as char[] on line 5
person.aaa:4:"name" defined as String but defined as char[] on line 6
person.aaa:5:"name" defined as char[] but defined as String on line 2
person.aaa:5:"name" defined as char[] but defined as String on line 3
person.aaa:5:"name" defined as char[] but defined as String on line 4
person.aaa:6:"name" defined as char[] but defined as String on line 2
person.aaa:6:"name" defined as char[] but defined as String on line 3
person.aaa:6:"name" defined as char[] but defined as String on line 4

Multiply Repeated Inheritance

One of the classic problems of object-oriented programming language design is that of Multiple Inheritance. Any object-oriented language that supports multiple inheritance must deal with the Diamond Problem, i.e. if class A inherits from classes B and C, and if B and C both inherit from class D, does A inherit one copy of D, or one copy from each of B and C, and if so, how are conflicts resolved?

AganeAndAgane solves this problem by providing Multiply Repeated Inheritance. In an AganeAndAgane application, a class can inherit from multiple base classes, as long as all the base classes are identical. For example, in the following code example, class Employee inherits from class Person seventeen times:

class Person:
  name: String;
  name: String;

class Employee > Person, Person, Person, Person, Person, 
                 Person, Person, Person, Person, Person, 
                 Person, Person, Person, Person, Person, 
                 Person, Person:
  salary: Money;
  salary: Money;
UML Diagram of Person and Employee Class

Figure 1: UML Diagram showing inheritance relationship between Person and Employee classes

Runtime Semantics

Implementing compile-time repetition-invariant semantics is relatively straightforward, but to fully support repetitionism in all aspects of application development, AganeAndAgane provides run-time repetition invariance.

Consider the following code fragment:

  salary = salary * (1 + salaryRaisePercentage/100);
  salary = salary * (1 + salaryRaisePercentage/100);
  salary = salary * (1 + salaryRaisePercentage/100);
  salary = salary * (1 + salaryRaisePercentage/100);
  salary = salary * (1 + salaryRaisePercentage/100);
  salary = salary * (1 + salaryRaisePercentage/100);
  salary = salary * (1 + salaryRaisePercentage/100);
  salary = salary * (1 + salaryRaisePercentage/100);

The programmer obviously intended to apply a salary raise percentage to an existing salary value. But did the programmer intend to apply the raise eight times?

How can we avoid this ambiguity, and achieve repetition-invariant runtime semantics? Those of you reading this article who are regular readers of Lambda the Ultimate will probably already have figured out the answer to this question: avoid destructive assignment, and require referential transparency.

The cause of the problem is that the "salary" variable appears on both the left and the right hand sides of the assignment operator. A referentially transparent alternative is the following code:

  newSalary = salary * (1 + salaryRaisePercentage/100);
  newSalary = salary * (1 + salaryRaisePercentage/100);
  newSalary = salary * (1 + salaryRaisePercentage/100);
  newSalary = salary * (1 + salaryRaisePercentage/100);
  newSalary = salary * (1 + salaryRaisePercentage/100);
  newSalary = salary * (1 + salaryRaisePercentage/100);
  newSalary = salary * (1 + salaryRaisePercentage/100);
  newSalary = salary * (1 + salaryRaisePercentage/100);

Here we put the updated salary value into a distinct variable "newSalary", and we no longer have to concern ourselves with whether the statement is executed eight times or just once.

Repetition Invariance and Idempotency

I mentioned earlier that AganeAndAgane is almost functional, and this is explained by the following code example:

  value = abs(value);
  value = abs(value);
  value = abs(value);
  value = abs(value);
  value = abs(value);

Here the variable "value" is being replaced by its absolute value. Because the function abs is idempotent, the assignment statement is repetition-invariant, even though the variable "value" appears on both sides of the assignment operator, so the AganeAndAgane compiler will compile this code without complaint. (There are some limitations to this relaxation, because the problem of determining idempotence is in general equivalent to the halting problem.)

Comment Repetition

Strictly speaking, comments are not part of the executable semantics of application source code, but in practice they are important for the purposes of documentation and maintenance. For this reason, the AganeAndAgane compiler will display warnings if incorrect comment repetition is detected. Command line options are available to either suppress these warnings, or, if necessary, raise them to the status of fatal errors.

For example, the following code has some incorrectly repeated comments:

class Person:
  age: integer; # The person's age
  name: String; # Their name
  age: integer; # The person's age
  age: integer; # How old they are
  age: integer; # How old they are
  name: String; # Their name

In default warnings mode, the compiler will output the following warning:

person.aaa:2:WARNING:Comment "The person's age" conflicts with comment "How old they are" on line 5
person.aaa:4:WARNING:Comment "The person's age" conflicts with comment "How old they are" on line 6
person.aaa:2:WARNING:Comment "The person's age" conflicts with comment "How old they are" on line 5
person.aaa:4:WARNING:Comment "The person's age" conflicts with comment "How old they are" on line 6
person.aaa:5:WARNING:Comment "How old they are" conflicts with comment "The person's age" on line 2
person.aaa:5:WARNING:Comment "How old they are" conflicts with comment "The person's age" on line 4
person.aaa:6:WARNING:Comment "How old they are" conflicts with comment "The person's age" on line 2
person.aaa:6:WARNING:Comment "How old they are" conflicts with comment "The person's age" on line 4

Appendix: Proof-Theoretic Repetition-Invariance

The repetition-invariant semantics of AganeAndAgane can be defined by the following Natural Deduction rules:

Repetition Introduction:

\[\frac{X \vdash A}{X \vdash A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; A}\]

Repetition Elimination:

\[\frac{X \vdash A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; A; A}{X \vdash A}\]
Vote for or comment on this article on Reddit or Hacker News ...