How to Improve Interfaces

The post is a mix of Java, Scala and some fantasy language. I use the code examples to explain my points not as actual working code

I really like interfaces. I wrote about them here. They feel clean to me. They abstract ideas and minimize the contract between classes. I encourage developers to develop against interfaces.

Instead of depend on a broad class,

public Boolean goodName(p:Person)

narrow the dependency down to

public Boolean goodName(n:Nameable)

This even made it onto my list for better Java. But beside adding Interfaces to the language, Java makes it hard to use interfaces.

For easier and broader usage of interfaces, my two wishes for a language to implement would be

  1. Interfaces for attributes
  2. Classes that do not implement an interface can still be used

With both of these one would get most of the dynamic 'quack-like-a-duck' power combined with compile time type safety.
There is one downside to implicit matching interfaces. By declaring implements one declares that a class follows semantically an interface. Implicitly this may not be the case.

[edit: Found today in a Golang presentation about implicit interfaces: "It's a form of duck typing, but (usually) checkable at compile time. It's also another form of orthogonality."]

Classes that do not implement an interface can still be used

Let's start with number 2. The easy solution is for a class that implements all the method of an interfaces but does not declare that it implements the interface. For example:

class Person {
    def getName():String = ....
}

interface Nameable {
    def getName():String
}

I now wish to use a person object with the method defined above

def goodName(n:Nameable):Boolean

goodName(new Person) // does not compile

In Scala this can be achieved with

goodName(new Person with Nameable)

- go try it yourself - but I'd wish the compiler would do this automatically (with caching the generated class) so I'd simply write

goodName(new Person)

When modifying instances (create Person with Nameable, cast (?) instance to new class) this also works where one has no control over the creation of Person (but I'm no JVM specialist):

def doSomething(p:Person) {
  val ok = goodName(p)
  // goodName(p with Nameable) does not compile
  ...
}

The harder case is when a class does not implement the method. For example a Person class

class Person(name:String)

does not implement Nameable and does not provide the necessary method. So we would need a language construct to extend the class with the missing methods.

extend Person with Nameable {
  def getName():String = this.name
}

Alternative syntax could be

extension Person with Nameable {
  def getName():String = this.name
}

extension Person implements Nameable {
  def getName():String = this.name
}

extension Person < Nameable {
  def getName():String = this.name
}

Person extend with Nameable {
  def getName():String = this.name
}

Person.Nameable {
  def getName():String = this.name
}

Person + Nameable {
  def getName():String = this.name
}

Another way would be to extend the Person class with extension methods, like Kotlin extends classes for example, until it satisfies the Interface. Then the automatic part above can apply.

func Person.getName():String {
  this.name
}

Go implements this in a nice way:

type geometry interface {
  area() float64
}

type rect struct {
  width, height float64
}

func (r rect) area() float64 {
  return r.width * r.height
}

func measure(g geometry) {
  fmt.Println(g.area())
}

func main() {
  r := rect{width: 3, height: 4}
  measure(r)
}

Both would make it much easier to work with Interfaces.

Interfaces for Attributes

I'm not a fan of getter and setters in Java. They add boilder plate code all the time and only very seldom I've encountered a problem that was solved by getter and setters. One argument for setters is value validation. I prefer to use validated types in this case with no need for a validating setter.

class Person(name:String)

could be implemented by

interface Nameable(name:String)

and be used in a method

def printName(n:Nameable) {
  println(n.name)
}

Interfaces for attributes might be controversial, but in languages with data classes or properties this could be very useful. I miss interfaces for attributes all the time in my Scala coding and I guess this happens to others as well in languages that do not push getters and setters like Java.

These two extensions to the power of Interfaces I'd love to see in a programming language. If I have more thoughts about interfaces I'll add to this blog post. The thoughts are also a base for my own programming language experiment.

How Scala can do this

There are some ways in Scala to bring Person and Nameable together. On way is with implicit classes (although I had to implement the method).

case class Person(n:String) { def name():String = n }

trait Nameable { def name():String }

implicit class NameablePerson(p:Person) extends Nameable {
  def name():String = p.name
}

def printName(n:Nameable) { println(n.name) }

printName(Person("Codemonkey"))

In Scala one might use Type Classes for implementing Nameable. Chris ( @cbirchall ) was kind enough to supply a gist

// Nameable is now a typeclass, not an interface
trait Nameable[P] {
  def getName(p: P): String
}

case class Person(name: String)
case class Dog(name: String)
case class Building(floors: Int)

// provide instances of the Nameable typeclass for Person, Dog, anything else you're interested in naming.
implicit val nameablePerson = new Nameable[Person] {
  def getName(p: Person) = p.name
}
implicit val nameableDog = new Nameable[Dog] {
  def getName(d: Dog) = d.name 
}

// you can also provide a fallback instance of the typeclass for any other type
// (the implicit vals above will take precedence over this for Person and Dog)
implicit def nameableAnythingElse[A] = new Nameable[A] {
  def getName(a: A) = a.toString
}

def doSomething[A](a: A)(implicit ev: Nameable[A]): String = {
  s"the thing's name is ${ev.getName(a)}"
}

A third option is with Scala structural types.

type Nameable = { def getName():String }

case class Person(n:String) { def getName():String = n }

def printName(n:Nameable) { println(n.getName()) }

printName(Person("Codemonkey"))

The downside are - alledged - performance problems with structural types and more important it does not play as nicely with Interfaces as an automatic approach.

If you have ideas about interfaces or general feedback, reply to @codemonkeyism

Stephan the codemonkey writes some code since 35 years, was CTO in some companies and currently helps startup with their technical challenges