PHP delegation vs. GoLang type embedding

One of the things I like the most about the Go programming language that I really wish PHP had is its type embedding.

And while legitimate Gophers know that Go is not exactly an object-oriented language, it has many features that allow leveraging OOP development experience so please permit me to discuss type embedding from an OOP perspective so it will be easier to understand by OOP developers.

PHP composition using delegation

In OOP languages like PHP, we have “inheritance” which allows classes to use the functionality of a more abstract class without having to implement it.

Consider a Block class for a desktop app with content properties and a render() method. With inheritance a developer can declare a AdvertBlock class which can inherit from the Block class and will automatically gain the Block‘s content property.

class Block {
    public $content;
    function render() {
        echo $this->content;
    }
}
class AdvertBlock extends Block {
    function __construct($advert) {
        $this->content = $advert;
    }
}
$avb = new AdvertBlock("<div class="ad"></div>");
$avb->render();

But in recent years, “thought leaders” in the development world have decided that Inheritance is bad and can no longer be discussed in polite company. The new king is Composition, and it is what everyone should be doing.

The problem is, if you use composition instead of inheritance in most OOP languages –– like PHP –– you end up having to write lots of methods that do nothing other than delegate from the contained class (e.g. Block) to the classes contain it (e.g. AdvertBlock), and you have to somehow provide an instance of the contained class when you instantiate it (as you see here in __construct()):

class AdvertBlock {
    private $_block;
    function __construct($block,$advert) {
        $this->_block = $block;
        $this->content = $advert;
    }
    function render() {
        $this->_block->render();  
    }
}
$avb = new AdvertBlock(new Block(), "<div class="ad"></div>");
$avb->render();

Now the above might not look so bad, but consider when you are dealing with tens of classes and and tens of methods for each class where you need to implement this delegation. That is a lot of boilerplate code to write (that, frankly, the language should handle for you.)

Worse consider when you add a method to one of your contained classes? Now you have to go back to each containing class and add a delegate method as well. Ugh.

Of course in PHP you can actually delegate automatically with the __call()magic method, but that is tedious to implement in all your classes, it has significant performance penalties to consider, and you still have to add a PHPDoc comment if you want your IDE to provide autocomplete and to stop flagging as an error. (And I did not even mention delegating properties via __get() and __set() methods!):

/**
 * @method render() void
 */
class AdvertBlock {
    private $_block;
    function __construct($block,$advert) {
        $this->_block = $block;
        $this->content = $advert;
    }
    function __call($method, $args) {
        $value = null;
        foreach( get_object_vars($this) as $name => $value ) {
            if ( method_exists( $this->$name, $method ) ) {
                $value = call_user_func_array([$this->$name,$method],$args);
                break;
            }
        }
        return $value;
    }
}

Still, even with all these downsides I still use this approach in all of my PHP projects because it is mostly better than not.) Ironically, one of the best ways to handle including this type of __call()method in all your PHP classes is to use some sort of BaseObject() class that you have all your other classes extend from. But I digress…

Go composition using type embedding

Once again, Go is not really an object-oriented language; one of the main things it does not support is inheritance. It also does not have classes, although it has structs which are a reasonable facsimile for those coming to Go from other OOP languages.

Since Go does not provide inheritance you must use composition for any sharing of functionality across structs. But here is where Go shines with its type embedding. Go provides automatic delegation when you embed at type; you do not have to maintain it like you do with PHP.

Let us revisit our simple Block and AdvertBlock example, this time using Go:

package main
type Block struct {
    Content string
}
func (b Block) render() {
    print(b.Content)
}
type AdvertBlock struct {
    Block
}
func NewAdvertBlock(a string) AdvertBlock {
    return AdvertBlock{Block{Content:a}}
}
func main(){
    avb := NewAdvertBlock("<div class=\"ad\"></div>")
    avb.render()
}

Easy, peasy!

Even better, you can run it in the Go Playground and/or iyou can tweak the code to see how it behaves given different code choices. Try changing the Block declaration embedded in AdvertBlock to *Block and see what happens (*Block means “a pointer to a Block.)


Proposal: Contracts in Go (Not Generics)

#Update

When I wrote this I did not remember that the draft design for Go2 generics chose to use the name “Contracts” for a new language feature to provide a Go-idiomatic response to generics.

Still, I stand by my use of the name contracts for this proposal as I think it is more in line with the use than the programming industry and used for decades, and that would the Go team named contracts would be better if they renamed it “Constraints”.

#Discussion

Discussion for this proposal is (mostly?) on Github.

Preface

I wanted to write this as a Go Experience Report (like this one), but my I felt that it would have simply taken simply too much time to explain my specific used case, and by then I would have lost the reader. So I decided instead to simple create a proposal instead.

Suffice it to say that it was my experiencing difficulties during development that caused me to write this, not a pie-in-the-sky desire for some shiny new feature. So I hope those in the Go community who prefer experience reports can forgive me for this transgression.

Problem Statement

In my experience, there are generally two broad use-cases for interfaces. The second is what Go is exceptional for; the one-method, implicitly-implemented “-er” type interface. I cannot gush enough how brilliant these are and how wonderfully they encourage serendipitous reusability.

That said, there is another type of broad use-case for interfaces, and it is the one commonly recognized by most other programming languages; the idea of a contract between caller and callee. In my experience I have generally seen the need for these when creating an extension API.

Basically this concept would be useful in Go when you want to explicitly indicate that a package is to be used as an extension for application code and this concept is usually described as a contract.”

An example of the type of extension might be a database driver — what they call a “dialect” — for GORM.

Proposed Addition

“Contracts” would be a new type in Go and would allow a developer to define a set of interfaces to comprise a contract plus then be able to reference the contract in a struct to enforce its usage

If contracts of this nature existed, maybe GORM would have used a contract and instead and created a collection of small interfaces rather than one large interface?

Example Declaration

Using the GORM Dialect type for our example, with a contract it they could make it look like this:

type Dialect contract {
	NameGetter
	DBSetter
	VarBinder
	Quoter
	DataTyper
	IndexVerifier
	ForeignKeyVerifier
	IndexRemover
	TableVerifier
	ColumnVerifier
	ColumnModifier
	LimitAndOffsetConstrainer
	DummyTableSelecter
	LastInsertIDReturningSuffixer
	DefaultValueStringer
	KeyNameBuilder
	CurrentDatabaseGetter
}

And here is what each of those interfaces could look like:

type NameGetter interface {
	GetName() string
}
type DBSetter interface {
	SetDB(db SQLCommon)
}
type VarBinder interface {
	BindVar(i int) string
}
type Quoter interface {
	Quote(key string) string
}
type DataTyper interface {
	DataTypeOf(field *StructField) string
}
type IndexVerifier interface {
	HasIndex(tableName string, indexName string) bool
}
type ForeignKeyVerifier interface {
	HasForeignKey(tableName string, foreignKeyName string) bool
}
type IndexRemover interface {
	RemoveIndex(tableName string, indexName string) error
}
type TableVerifier interface {
	HasTable(tableName string) bool
}
type ColumnVerifier interface {
	HasColumn(tableName string, columnName string) bool
}
type ColumnModifier interface {
	ModifyColumn(tableName string, columnName string, typ string) error
}
type LimitAndOffsetConstrainer interface {
	LimitAndOffsetSQL(limit, offset interface{}) string
}
type DummyTableSelecter() interface {
	SelectFromDummyTable() string
}
type LastInsertIDReturningSuffixer() interface {
	LastInsertIDReturningSuffix(tableName, columnName string) string
}
type DefaultValueStringer() interface {
	DefaultValueStr() string
}
type KeyNameBuilder() interface {
	BuildKeyName(kind, tableName string, fields ...string) string
}
type CurrentDatabaseGetter() interface {
	CurrentDatabase() string
}

Isn’t this more like idiomatic Go?

Example Usage

Then to use a contract in a struct, just embed it as you would another struct. The following example embeds our hypothetical contract named gorm.Dialect. Very simple:

type OracleDialect struct {
    gorm.Dialect
    // Properties go here
}
// Methods go here

Additional Enhancements

Beyond the simple addition of contracts there are a few other features I think would really be beneficials for these proposed contracts.

Allow Interfaces to be Optional

One of my biggest complaints with interfaces in other languages is their fragility. They can never accept backward compatible changes once they have been “released into the wild.” The ability to define implementation of an interface as optional would go a long way to making contracts more resilient over time. It would also allow contract designers to specify which methods implementers can ignore if they do not need them.

Revisiting our Dialect contract from above, here is what it might look like with an optional keyword:

type Dialect contract {
	NameGetter
	DBSetter
	VarBinder
	Quoter
	DataTyper
	IndexVerifier
	ForeignKeyVerifier
	IndexRemover
	TableVerifier
	ColumnVerifier
	ColumnModifier
	LimitAndOffsetConstrainer
	DummyTableSelecter
	LastInsertIDReturningSuffixer optional
	DefaultValueStringer optional
	KeyNameBuilder
	CurrentDatabaseGetter
}

Allow Interfaces to be Added

Now I realize that over time developers might add methods to contracts and mark them as optional to support backward compatibility even though they might not be optional for newer use-cases. If this is seen as a significant problem then maybe added [`<ver_tag>`] could be used to specify that a method is in fact optional but only for backward compatibility reasons and that newer implementers should use it.

Contacts would also allow IDEs like GoLand to optionally enforce the need the interface to be implemented, if they chose to do so.

Counter Argument

So what do I anticipate the counter argument to be?

Go does not need a new type

I assume a seasoned Go developer might say:

“We can already do “contracts” just by embedding an interface into another interface. We don’t need a new named — let’s keep Go — and just allow interfaces to be explicitly implemented in a struct to address this use-case.”

And they would be right. Frankly, that was my first thought too.

Rebuttal

But then I remembered one of the best things about Go interfaces is they are implicit, and when small they can empower serendipitous reusability. But Go currently encourages large interfaces for these use-cases, and from an idiomatic perspective, I believe that is bad behavior.

Contracts would discourage large interfaces

If Go adds a new contract type, and the contracts only supports aggregation of interfaces with not direct inclusion of method signatures then many small interfaces would actually be encouraged.

There would also be be a clear and distinct difference in intended use-case for contracts vs. interfaces.

Summary

So, since:

  1. Programming educators have been using “contract” to explain interfaces for decades,
  2. A contract type would obviously be easy to reason about
  3. This is a use-case for interfaces that Go does not yet accommodate,
  4. I do not think this would make Go programs more fragile or complex, and
  5. (I think) it would not have any backward compatibility issues.

I contend this would be a great addition to Go.

What do you think?

GoLang Strict Typing and Interface Slices

This is a GoLang Experience Report.

…but you cannot define the rows parameter as type []RowInserter because []interface{} won’t match it, even though RowInserter is itself an interface.

Background

I am relatively new to programming Go, but I have been developing software professionally in a variety of programming languages on and off since the late 80’s. Go’s concept of a language in service of software engineering resonates with me greatly, and as such I am very interested in learning and using idiomatic Go.

Regarding my experience report, an advocate of adding generics to Go will read this post and declare it illustrates why Go needs generics. I however, am not a fan of generics, at least not how they have been implemented in other C-like languages. Thus I would prefer Go find an easier-to-reason-about method for handling concerns like I am reporting.

Scenario

Consider a scenario where you have a slice of a concrete struct. Let us call that struct’s type Item for our example. And let us also assume these Items implement a RowInserter interface which requires an InsertRow() method be declared:

type Item struct {
   id int
}
type RowInserter interface{
    InsertRow()	
}
func (i *Item) InsertRow() {
   fmt.Printf( "Item id=%d inserted.\n",i.id )
}

Since, for many of my use-cases, the insertion of rows is fairly generic I would like to create a general-purpose package with a method you just pass a slice of Items to and have it loop through the rows to insert the item by calling the items’ InsertRow() method for each item.

Here is a main() that creates there items and then calls my desired InsertRows() function as I just described:

func main() {
   items := make([]*Item,3)
   for i := range []int{1,2,3} {
	items[i] = &Item{i}
   }
   InsertRow(items) // This won't work...
}

But of course the above does not work.

Instead we need to first loop through the slice of Items and add them to a slice of interface{}.

We could have littered our main() with this code, but instead I created an InsertItems() function that does the looping for us:

func InsertItems(items []*Item) {
    rows := make([]interface{}, len(items))
    for i, item := range items {
        rows[i] = item
    }
    InsertRows(rows)
}

Now we can implement our “generic” InsertRows(). However, and here is one of the main tricks, you cannot define the rows parameter as type []RowInserter because []interface{} won’t match it, even though RowInserter is itself an interface:

func InsertRows(rows []interface{}) {
    for _,r := range rows {
        r.(RowInserter).InsertRow()
    }
}

I have added all the the above in the Go playground. Please try it for yourself.

(Or maybe I just do not know how to make this easier to work with? Please comment if you know otherwise.)

Suggestion

Since InsertRows() accepts a parameter that is a slice of interface{} it would not violate type safety, other than in the most rigid perspective, for a slice of another type to be passed in and automatically converted to a slice of interface assuming the types satisfy the interface used.

Even better would be for when we want to pass a slice of types (e.g. []*Items) that implement a specific interface (e.g. RowInserter) are passed to a function that accepts a slice of that interface (e.g. []RowInserter) then Go could validate the elements of the slice for type safety and not the entire composite type.

Then my example could be simplified greatly to the following, and would also be much easier to reason about:

package main

import (
    "fmt"
)

type Item struct {
   id int
}

func main() {
   items := make([]*Item,3)
   for i := range []int{1,2,3} {
	items[i] = &Item{i}
   }
   InsertRows(items) 
}

func (i *Item) InsertRow() {
   fmt.Printf( "Item id=%d inserted.\n",i.id )
}

type RowInserter interface{
    InsertRow()	
}

func InsertRows(rows []RowInserter) {
    for _,r := range rows {
        r.InsertRow()
    }
}

Also, this same should apply for maps as well asfor slices, assuming the map keys are the same type.