Perl-Apollo / Corinna

Corinna - Bring Modern OO to the Core of Perl
Artistic License 2.0
157 stars 19 forks source link

Interfaces #24

Closed jpr65 closed 3 years ago

jpr65 commented 3 years ago

In most OO languages you have "interfaces".

DBI is the DataBase Interface on CPAN but not a really interface. But it could be.

An interface is something like a role with only abstract methods and it is not possible to create instances of interfaces.

Or you can say: an interface is a abstract role.

You can derive interfaces like roles and classes.

An interface defines methods, that can be called on an object and the programmers use interfaces instead of classes like this:

interface IEnumeration {
    method entries();
    method add($str);
}

interface IList isa IEnumeration {
    method count();
}

class List implements IList {
    has @list_entries;
    method entries()  {
        return @list_entries;
    }
    method add($str) {
        push @list_entries, $str;
    }

    method count() {
        return scalar @list_entries;
    }
}

 my $list is IList = List->new;

 $list->add("a String value");

 foreach my $l ($list->entries) {
   say $l;
}

 $list->count(); # error, because count is no method of interface IEnumeration

With interfaces, it is possible to create a DB-access-factory like this:

my $dbi_read = $DBI->database_accessor_readonly("Server", "MyDatabase");

foreach my $row ($dbi_read->query(...)) {
     say $row->print();
}

and you cannot call Insert(), Update() or Delete() on $dbi_read, because database_accessor_readonly() returns interface IDbRead.

my $dbi_rw = $DBI->database_accessor_rw("Server", "MyDatabase");

can do Query() and Update(), because it returns IDbReadWrite.

my $dbi = $DBI->database_accessor_full("Server", "MyDatabase");

can do Query(), Insert(), Update() and Delete(), because it returns IDbFullRowAccess;

But it cannot create oder drop tables.

interface IDbRead {
    method Query(...);
}

interface IDbReadWrite isa IDbRead {
    method Update(...);
}

interface IDbFullRowAccess isa IDbReadWrite {
    method Insert(...);
    method Delete(...);
}

And everything is implemented in the same class DBI::MySql:

class DBI::MySql implements IDbFullRowAccess {
    method Query(...);
    method Update(...);
    method Insert(...);
    method Delete(...);
}
Ovid commented 3 years ago

We have interfaces. They are simply roles without default implementations. The only question is whether or not we'll use requires or abstract:

role IDbFullRowAccess {
    requires qw(
        query
        update
        insert
        delete
    );
}

versus:

role IDbFullRowAccess {
    abstract method query (...);
    abstract method update (...);
    abstract method insert (...);
    abstract method delete (...);
}
Ovid commented 3 years ago

Oops. Closed this by accident. I'll close it again later unless someone points out some flaw in the Corinna approach.

jpr65 commented 3 years ago

I prefer "abstract". This is needed for methods with different signatures, but same name.

leonerd commented 3 years ago

Recent discussions wondered if we even need the abstract word at all; whether just giving a prototype with no definition is sufficient:

role Bouncable {
    method bounce($height);
}
Ovid commented 3 years ago

@leonerd I think you're right that a method forward declaration would be sufficient. However, if we're to allow abstract classes, we would have to have that on the class declaration. Using the example from my last talk:

abstract class Boolean {
    method ifTrue ($code) {}
    method ifFalse ($code) {}
}

Here we must declare the class as abstract because it must not be instantiated directly, even though it doesn't have any abstract methods.

Ovid commented 3 years ago

This is resolved for the MVP. Further issues should be new tickets.