NAME

Data::CapabilityBased - Ask your data not what it is, but what it can do for your program

SYNOPSIS

use Data::Store;
use Data::Collection;
use Data::Stream;
use Data::Query;

DESCRIPTION

The Data::CapabilityBased module itself is, and will always be, an empty placeholder providing an overview of the concepts of the project and links to the known distributions making use of this code. Sub namespaces of this module will likely contain helper modules to ease bla blah finish this bit when we find out if we need them.

This distribution is uploaded in the absence of code in order to function as a central point to document the design of the capabilities as we flesh them out and start building the compliance suites; please see the Data::Store, Data::Collection, Data::Stream, Data::Query for the progress made so far towards this.

MANIFESTO

The principle behind this system is: when you're being passed something that's being treated as simply data, you shouldn't be thinking about -what- you've been passed but merely whether you can use it in the manner you need to. So, to pick an example I deal with every day, you have code that needs to process a set of objects. Think -

method do_something ($to) {
  foreach my $target (@$to) {
    $to->frotz;
  }
}

Now, of course, this is great if $to is an arrayref. But otherwise you're in trouble. So, you think "hey, I'll add a type check:"

method do_something ($to) {
  confess "Dammit, Jim, I'm a deckchair not an osculator"
    unless ref($to) eq 'ARRAY';
  ...
  

But now what happens if it's an object that arrayifies? BOOM. (a good example of this from my world would be a DBIx::Class::ResultSet).

Well. We could test it's something that arrayifies:

method do_something ($to) {
  confess "Out of Cleese error. Call stack has Goon away."
    unless (ref($to) eq 'ARRAY' || (blessed($to) && $to->can('(@{}')));
  ...

but for a start that's really ugly, and more importantly it only handles the case that we want to do @$to. Which is probably fine, except now we're going to slurp whatever contents of that resultset were into memory at once. If it contains a million records, we just made your computer cry (and probably your sysadmin developercidal).

So, what's a better approach? Well, what if we could say to our data "hey, I know you're capable of returning me a series of objects, but I really just want to run something on all of them" - so, something like

method do_something ($to) {
  $to->each(sub { $_->frotz });
}

but then how do we know if this is something that can provide a suitable each method ... and what do we do about plain arrayrefs, which don't have methods at all? Well, given autoboxing can provide an ->each method on an arrayref, we can do something like:

use Data::Collection::Capabilities qw(Eachable);
use Data::Collection::Autobox;

method do_something (Eachable $to) {

and then an arrayref will be automatically autoboxed with an ->each method that supports this interface, and report that it provides the capability, and a collection object that declares its capabilities will pass the type test as well.

AUTHOR

Matt S. Trout (mst) <mst@shadowcat.co.uk> http://www.shadowcat.co.uk/

LICENSE

This library is free software under the same license as perl itself.