Fluent interfaces in Perl 6

I've been digging into Perl 6 more lately and I noticed the Wikipedia example of fluent interfaces didn't have a Perl 6 example, so I fixed that.

To be fair, Martin Fowler's explanation (as usual) of fluent interfaces does a much better job of explaining them, but a key point is that setters have a return value. For many fluent interfaces, the setters set a value and actually return a new instance of a different object for you to call methods on. Thus, the examples in Wikipedia don't always meet the criteria of a fluent interface, but I added a Perl 6 version that closely modeled the PHP version (but more concisely, and with much better type safety). I sidestepped the entire fluent interface debate.

Here's my example:

class Employee {
    subset Salary         of Real where * > 0;
    subset NonEmptyString of Str  where * ~~ /\S/; 

    has NonEmptyString $.name    is rw;
    has NonEmptyString $.surname is rw;
    has Salary         $.salary  is rw;

    method gist {
        return qq:to[END];
        Name:    {$.name}
        Surname: {$.surname}
        Salary:  {$.salary}
        END
    }
}
my $employee = Employee.new();

given $employee {
    .name    = 'Sally';
    .surname = 'Ride';
    .salary  = 200;
}

say $employee;

And that prints:

Output:
Name:    Sally
Surname: Ride
Salary:  200

The lovely folks on the #perl6 IRC channel helped me fix a few misunderstandings (they're really awesome), and once again, I find Perl 6 is just a joy to work with.

11 Comments

Cool!

One remark: you don't need a closure for showing an attribute in a string, so:

qq/Name: $.name/

will just do fine!

How would you write Martin Fowler's JMock example (which you linked to) in Perl 6?

Is there a way to get perl6 to generate an error message if a grammar does not match? Or at least return the position of the last data it processed? It is quite hard to fix syntax errors if all I get from the parser is 'no match'.

I'm not fluent in Perl6, but I don't see any fluent interface happening here. I'd expect something like


$employee.name('Sally').surname('Ride').salary(200);

Ovid - cool on you for taking the time to spread Perl6 knowledge, especially on such an important site as Wikipedia - keep up the good job :)

However...

"Perl 6 uses different idioms and the given idiom above is more natural for the language."

If that's really the case it would personally make Perl6 a pain to read and I hope (again personally, YMMV) that it's not true. Sorry :(

say $employee.name('Sally').surname('Ride').salary(200);

Seems natural to me and forces me to understand nothing about the internal structure of $employee (only the external API).

"given" is a flow control structure. Using it the way you have feels disconnected to me, there's no visible connection to the following "say" statement. Also you are directly setting attributes, rather than using a public API - isn't that usually something bad in OO code?

I like the general direction Perl6 took but some of the details, such as over-reliance on sigils (more line noise) really grate at me. If directly accessing object internal variables instead of using setters is now considered natural/best-practise in Perl6... I don't know... Maybe I don't understand real programming but I know what I like and this, I don't.

Also you are directly setting attributes, rather than using a public API - isn't that usually something bad in OO code?

Attributes in the interface don’t have to translate to fields in the class and assignments to such attributes don’t have to mean unchecked writes to private fields. It’s trivial to provide the same attribute interface outwardly but actually implement it with accessors/mutators behind the scenes.

Just because that code would be bad in Java doesn’t mean it’s bad in Perl 6.

Great news, I love Perl. Thanks a ton

About Ovid

user-pic Freelance Perl/Testing/Agile consultant and trainer. See http://www.allaroundtheworld.fr/ for our services. If you have a problem with Perl, we will solve it for you. And don't forget to buy my book! http://www.amazon.com/Beginning-Perl-Curtis-Poe/dp/1118013840/