Объекты? Зачем?! Точнее, не всегда. Замыкания!

Заметка не предназначена для разжигания священной войны: хорошо или плохо объектно ориентированное программирование. Я сам использую его наравне с другими.

Цель заметки --- показать, что иногда проще обойтись без объектов, а использовать замыкания.

Достаточно часто возникает ситуация, когда необходимо многократно произвести некоторое действие, но перед этим провести некоторую подготовительную работу. В объектно ориентированном стиле для этого используется объект с одним единственным методом.

Рассмотрим подобный объект на примере абстрактного "сумматора" чисел. При инициализации "сумматору" передается первоначальное значение, а при каждом вызове метода к текущему значению прибавляется передаваемое. Вот код такого "сумматора" в объектно-ориентированном стиле:

 package Foo;
 sub new {
  my $class = shift;
  my $foo = shift;
  return bless \$foo;
 }
 sub foo {
  my $self = shift;
  $$self += shift;
  print $$self, "\n";
 }
 1;

Пример использования:
 use Foo;
 my $foo = Foo->new(3);
 $foo->foo(1);
 $foo->foo(1);
 $foo->foo(2);
 $foo->foo(2);

Теперь сделаем аналогичный по функционалу "сумматор" с использованием замыкания:
 sub make_foo {
  my $foo = shift;
  return sub {
   $foo += shift;
   print $foo, "\n";
  };
 }

Пример использования:
 my $foo = make_foo(3);
 $foo->(1);
 $foo->(1);
 $foo->(2);
 $foo->(2);

Как видим вариант с замыканием проще, компактней и элегантней.

Пожалуй на этом и остановимся --- читатель дальше сможет сам развить тему. Приведу лишь цитату Стива Маджевски: "Объект --- это совокупность данных вместе с привязанными к ним процедурами... Замыкание --- это процедура вместе с привязанной к ней совокупностью данных."

P.S.
Кстати, Parrot оперирует объектами (PMC),
но при вызовах подпрограмм использует стиль передачи продолжений, который не мыслим без замыканий.

P.P.S.
Оригина находиться на http://aziness-impatience-hubris.blogspot.com

камент

Обжекты рулят.

#!/usr/bin/perl -w
package Adder;
 sub new{return bless\$_[1]}
 sub add{print(($$_[0]+=$_[1])."\n");return$_[0]}1;
package main;
new Adder(0)->add(3)->add(4)->add(1)->add(10)

alpha@alpha ~ $ ./adderoop.pl
3
7
8
18
alpha@alpha ~ $

ссылку в ззы пофикси.

-- perl -e 'sub _{{{{{{{{print for fun}}}}}}}}_'

Спасибо, в

Спасибо, в некоторых случаях, как указано в заголовке, действительно удобнее.

Не спорю

> cat foo.pl
sub make_foo {
        my $foo = shift;
        my $sub;
        $sub = sub {
                $foo += shift;
                print $foo, "\n";
                return $sub;
        };
}
my $foo = make_foo(3);
$foo->(1)->(1)->(2)->(2);
> perl foo.pl
4
5
7
9

;-)

А как такой

А как такой объект сериализовывать?
Storable, как я понимаю, sub не переварит...

холивор :)

nick написал
> cat foo.pl
sub make_foo {
        my $foo = shift;
        my $sub;
        $sub = sub {
                $foo += shift;
                print $foo, "\n";
                return $sub;
        };
}
my $foo = make_foo(3);
$foo->(1)->(1)->(2)->(2);
> perl foo.pl
4
5
7
9

;-)

А наследование слабо? :)

-- perl -e 'sub _{{{{{{{{print for fun}}}}}}}}_'

Storable

rewlad написал
А как такой объект сериализовывать?
Storable, как я понимаю, sub не переварит...

pureperl'овый не переварит, а xsub'овый может переварить.

-- perl -e 'sub _{{{{{{{{print for fun}}}}}}}}_'