?

Log in

No account? Create an account

Tue, Dec. 18th, 2007, 09:44 am
Young, dumb, don't see a problem

I've been occasionally reading the O'Reilly Beautiful Code blog which accompanies the book of the same name. I have to admit I haven't agreed with all of it - some of it reads similarly to occasional posts I see scattered around the Interweb by Pattern Language zealots who haven't quite grasped that what they're doing is only because their chosen language is broken. It's not wrong per se it's just that, well, can a best-practices work around ever be considered beautiful.

Either way, I was pointed at this post this morning about The Cardinality of a Fluent Interface. Again, I wasn't entirely sure I agreed but I was sufficently intrigued to start hacking around.

My first attempt yielded something surprisingly elegant (despite using a couple of mildly egregious hacks such as abusing an overload of the concatenation operator) which allowed you to do things like
    one.hundred
    twenty.two
A slight bit of hackery later and it could also do
    six.hundred.and.fifty
Making it do
    four.point.zero
    point.five
    three.point.one.four
    one.nine.zero.four
Required changing the object from the oddly satisfying bless scalar to a more complicated blessed hash and the internals got a lot uglier. I was initially skeptical that I could make it do both nine.point.five.five - which is arguably the correct english way to say it - and nine.point.fifty.five - which is semantically also correct (albeit clumsy and ugly) and useful for currency - but then I suddenly had a flash of inspiration and hacked in the two line change.

Currently it's labouring under the name Acme::Numbers and not on CPAN but feel free to have a look and suggest new test case.

Tue, Dec. 18th, 2007 09:06 pm (UTC)
sodabrew

Very cool hack!

In Numbers.pm, this ain't right:
print four.pounds.fifty.pence."\n"; # prints "4.55"

Wed, Dec. 19th, 2007 12:24 am (UTC)
deflatermouse

Fixed. Also, I mistakenly thought you were reporting an actual bug instead of a documentation bug. it turns out that there was a bug with four.pounds.fifty.pence but it's fixed now.

Tue, Dec. 18th, 2007 10:33 pm (UTC)
2shortplanks

It's late, I haven't got time to look at the code, and I've got to prepare the house for the infant arriving tomorrow, but here's a suggestion:

Why do you need the concatination operator? Can't you just abuse the function prototype
sub(;$)
so you can write:

four point five


which really is:

four(point(five()))

Wed, Dec. 19th, 2007 12:29 am (UTC)
deflatermouse

I had a quick shot at trying this using
    use Scalar::util qw(set_prototype);
    *{"$pkg\::$num"} = set_prototype(sub { $class->$num(@_) }, ';$');

But I couldn't get it working properly.
    one->hundred

works ok so it should be possible but my brain is tired. Patches are, as they say, welcome. Although I imagine that you have enough on your plate ;)