LINUX.ORG.RU

Возможна ли подобная инкапсуляция в Perl?

 ,


1

2

Очень хочется делать так:

Описание класса:

package Object;
use strict;
use warnings;
our @EXPORT_OK=qw(new set_a get_a);
my $a='Hello';

sub new {
 bless {},shift
};

calc_a {
 my $v=shift;
 $v.=' here'
}

sub set_a {
 my $slf=shift;
 $a=calc_a(shift)
};

sub get_a {
 return $a
};

1;

Использование класса:

package main;
use strict;
use warnings;
use Object;

my $inst1=Object->new;
my $inst2=Object->new;

$inst1->set_a('Hot dog');
$inst2->set_a('Hot girl');

print join(' ','1)',$inst1->get_a,'2)',$inst2->get_a)."\n";

# $inst1->calc_a('Crazy man');

В результате должно быть выведено:

1) Hot dog 2) Hot girl

А если я раскомментирую последнюю строчку в main - Perl мне должен сказать «No such symbol calc_a in package Object» или что-то вроде этого - я же эту процедуру не экспортировал, а значит это «приватный метод».

Правильно ли я понимаю, что в Perl нельзя сделать так, чтобы переменные уровня пакета, в котором описан класс, были всё-таки переменными инстанса класса (конкретного объекта), а не просто переменными пакета?

Хранить данные в виде чего-то вроде $Config{refaddr $self}{'verbose'} - это по-моему извращение ещё более дикое, нежели хранение вообще всех данных внутри этой несчастной «благословлённой» (blessed) ссылки...

То есть чего бы хотелось:

1) чтобы при создании нового объекта происходило примерно то же, что и при fork'е процесса: все переменные пакета с их значениями копировались бы в адресное пространство объекта либо сразу, либо при первой же записи в них (а то копировать прямо всё и сразу может быть накладно).

2) нужно обязательное разделение методов на «приватные» и «публичные», чтобы я мог внутри объекта использовать те или иные процедуры, разрешая пользоваться извне лишь небольшим их подмножеством.

Можно ли как-то вот этак сделать в Perl или категорически нельзя?

P.S. Кстати, хранение всех собственных данных объекта в каком-нибудь громадном хэше, доступном по ссылке $ObjectData{refaddr $self}, то есть что-то вроде $ObjectData{refaddr $self}{'options'}{'user-defined'}{'var-a'} - это разве эффективно хотя бы с точки зрения скорости работы приложения? Как бы ни были эффективны хэши в Perl, по-моему все эти многоуровневые индексы куда менее эффективны, нежели простые переменные.

★★★★★

Последнее исправление: DRVTiny (всего исправлений: 2)
package Test;

sub new {
    my $class = shift;
    my $self = {};
    bless $self, $class;
    return $self;
}

sub getValue {
    my $self = shift;
    $self -> {theValue}; # '->'
}

sub setValue {
    my $self = shift;
    my $value = shift;
    $self -> {theValue} = $value; # '->'
}

package main;

my $inst1 = new Test;
my $inst2 = new Test;

$inst1->setValue('Hot dog');
$inst2->setValue('Hot girl');

print join(' ','1)',$inst1->getValue,'2)',$inst2->getValue)."\n";

Deleted
()
Ответ на: комментарий от anonymous

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

Посмотрите мой пример: здесь объект $inst1 и $inst2 модифицируют одну и ту же несчастную переменную $a. Как говорится, кто бы мне объяснил, зачем было нужно реализовать классы в Perl именно таким странным способом.

Именно поэтому каждому методу объекта передаётся ссылка на объект 1-м параметром: сомнительной ценности возможность доступа к методам и свойствам объекта изнутри самого объекта - в лучшем случаем третична, а первично то, что в Perl иначе и невозможно получить доступ к собственно данным объекта!

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

Ну, ok. А смысл? Это переменные относящиеся к инстанцам класса, поэтому и должны лежать в self.
(ну или да, заводить внутрепакетный маппинг созданных инстанцов к содержанию). Олсо, возможно изначальную проблему решит какая-ниюудь фабрика ведущая учёт созданных объектов.

anonymous
()
Ответ на: комментарий от DRVTiny

Посмотрите мой пример: здесь объект $inst1 и $inst2 модифицируют одну и ту же несчастную переменную $a.

заводи хеш, а в нём по имени модуля(если хочется каждому модулю отдельные переменные) или по адресу объекта(если для каждого объекта) другой хеш, с 'переменными'.
Или просто использую уже готовые OOP библиотеки, которые это всё сами делают(http://habrahabr.ru/post/146442/).

Как говорится, кто бы мне объяснил, зачем было нужно реализовать классы в Perl именно таким странным способом.

потому что они были добавлены потом, сбоку бантиком на соплях.

Bad_ptr ★★★★★
()
Последнее исправление: Bad_ptr (всего исправлений: 1)
Ответ на: комментарий от Deleted

Да в том-то и дело, что хранить все данные объекта в self'е - это какое-то дикое извращение.

У меня есть код, в котором, например, есть хэш

my %Config = ('default_params'=>{'wildcards'=>'true'})

Если я сделаю этот код объектно-ориентированным, то у меня будет что-то вроде:

$self->{'config'}{'default_params'}={'wildcards'=>'true'};

Что меня в этом коробит больше всего?

Индекс с «красивым» названием config, которому раньше соответствовало имя переменной. Такое впечатление, что внутри этой несчастной ссылки self я должен прямо-таки воссоздать «пространство имён Perl». Жесть какая-то, особенно на фоне того, что в далеко не самом совершенном ОО-языке Visual Basic код работает именно так, как я (и любой нормальный человек) хотел бы.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

еси чё есть ещё такая штука как AUTOLOAD, может пригодится)

Bad_ptr ★★★★★
()
Ответ на: комментарий от anonymous

Было бы правильно, если бы при создании нового объекта его описание, находящееся в

package Class::Definition;

копировалось в новое пространство имён:

package Class::Definition::Inst01234;
Где Inst01234 - это идентификатор инстанса объекта

И тогда при обращении к методу объекта, этот метод получал бы окружение пакета Class::Definition::Inst01234б, а не Class::Definition!

По-моему так делается во всех нормальных ООП-языках...

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

Например:

sub getConfig {
  my ($self) = @_;
  return $self->{'config'}
}

sub blaBla {
  my ($self) = @_;
  $self->getConfig()->{'blaBla'}
}

anonymous
()
Ответ на: комментарий от anonymous

Так чего же странного? Вы где-нибудь ещё, кроме как в Perl'е, видели, чтобы все данные объекта лежали в одной чудесной переменной-ссылке?

Во всех известных мне языках если человек пишет описание класса, то он понимает, что переменные, описанные в нём, будут «индивидуальны» для каждого объекта, и для этого не нужно воротить никаких костылей: класс - это просто шаблон, а объект - это конкретная реализация этого шаблона.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

Nope; То что в пакете мимкрирует под static. Хотя твою хотелку можно поппробовать реализовать насилуя $package, но сразу не придумывается. Попробуй таки moose.

anonymous
()
Ответ на: комментарий от anonymous

// хотелку понял, но ИМХО в целом не проблема при наличии сеттеров, геттеров. Олсо можно попробовать добавлять переменные на лету из «первого» среза %

anonymous
()
Ответ на: комментарий от anonymous

хотелку понял, но ИМХО в целом не проблема при наличии сеттеров, геттеров.

Использовать сеттеры и геттеры прямо в самом коде класса - безусловно, бывает удобно, если логика сеттера или геттера достаточно сложная. Но если нужно просто присвоить переменной объекта заведомо «безопасное» значение, то вызов процедуры вместо просто $a=«value» может быть, мягко говоря, оверхедом (я много программировал на ассемблере и в общем представляю, насколько простое присвоение значения переменной может быть менее затратным, нежели вызов процедур)...

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Хотя твою хотелку можно поппробовать реализовать насилуя $package

Ага :)

Вопрос именно об этом :) Вдруг кто-нибудь уже пробовал. То есть буквально «устанавливать» текущее пакетное окружение в каждом методе объекта, чтобы объект работал заведомо со своим окружением и со своими переменными.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Moose, кстати, таки методы генерит. // Асм привычки в perl никому не нужны. // tldr; монастырь, устав

anonymous
()
Ответ на: комментарий от anonymous

Just for stupid fun ```perl package wow; { sub new { my ($class, $name) = @_; my $self = { name => $name};

return bless sub { while (($key,$value) = each %{$self}) { no strict 'refs'; ${«$key» . «_wow»} = $value; }; $self; } => $class; }

sub printName { my ($self) = shift->(); print $name_wow; } } 1; ``` use lib '.';

use warnings; use strict;

use Data::Dumper;

use Wow;

my $a = wow->new('yay1');

print(Dumper $a);

$a->printName();

print «\n»; # or say ```perl

```

anonymous
()
Ответ на: комментарий от anonymous

Сорь, перепутал:

package wow;
{

    sub new {
	my ($class, $name) = @_;
	my $self = { name => $name};

	return bless sub {
	    while (($key,$value) = each %{$self}) {
		no strict 'refs';
		${"$key" . "_wow"} = $value;
	    };
	    $self;
	} => $class;
    }

    sub printName {
	my ($self) = shift->();
	print $name_wow;
    }
}
1;

use lib '.';

use warnings;
use strict;

use Data::Dumper;

use Wow;

my $a = wow->new('yay1');

print(Dumper $a);

$a->printName();

print "\n";


my $b = wow->new('nope');


$a->printName();
$b->printName();

anonymous
()

эти многоуровневые индексы куда менее эффективны, нежели простые переменные

А я вот в этом не уверен. Т.к. «простая переменная» в динамическом языке вроде перла, суть тот-же хэш с сахарком.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от no-such-file

Oh, wow. Пропустил. Если ОП делает ради мифической производительности, то пусть возвращается в асм-мирок.

anonymous
()
Ответ на: комментарий от anonymous

Moose не решает ни проблему с переменными, которые непонятно с какого бодуна могут модифицировать все инстансы класса, ни с процедурами/функциями, которые не могут быть приватными:

package MooseTest;
use Moose;
my $a='Variable-slut, which may be "used" by any Moose object';

has propa => ( 'is' => 'rw', 'isa' => 'Str' );

sub do_smth {
 print "Hello, world!\n"
}

1;

DRVTiny ★★★★★
() автор топика
Последнее исправление: DRVTiny (всего исправлений: 1)
Ответ на: комментарий от anonymous

Мне нужно, чтобы одна и та же процедура работала с разными переменными в зависимости от того, методом какого объекта она является. Только и всего. Если запихивать все переменные в одну структуру - то в таком случае мне вообще нафиг не упёрся ООП, я могу просто идентификатор какой-нибудь передавать в обычные функции и процедуры. Причём крутизна такого подхода ещё и в том, что я могу и НЕ передавать идентификатор вообще, реализуя логику «если идентификатор не передан, то считать идентификатор=последнему_созданному». В убогом Perl'овом ООП такой логики нет: там хочешь или не хочешь, но все методы будет пихаться эта чудесная «благословенная» ссылка, а вместо просто do_smth придётся писать каждый раз MyObject->do_smth (как все мы помним, в Perl'е нет оператора «with»). Зачем это нужно?

DRVTiny ★★★★★
() автор топика
Последнее исправление: DRVTiny (всего исправлений: 2)
Ответ на: комментарий от DRVTiny

то в таком случае мне вообще нафиг не упёрся ООП

Ты познал дзен.

no-such-file ★★★★★
()
Ответ на: комментарий от DRVTiny

как все мы помним, в Perl'е нет оператора «with»

for($perl) {
  $_->getFun();
}

Переменные в package - это переменные класса. Переменные в ссылке - это переменные объекта.
Нафигач всяких аксесоров, если боишься опечататься в $qq->{string}. Хз, те. по мне проблемы особой нету, просто тут так принято by design и никто особо проблему в этом не видит. Выбери ruby тогда или ещё что-нибудь.

Happy Holidays

anonymous
()
Ответ на: комментарий от DRVTiny

программировал на ассемблере

Первая ошибка для перловика, питониста, рубиста, и т.д.: пытаться оптимизировать неоптимизированное. Ты прав, но это бесмысленно: перл настолько напичкан функциями обертками, что твоя оптимизация будет работать только в рамках также хорошо оптимизированного кода. Увы 95% модулей на CPAN совсем не оптимизированны (даже те, что написаны в XS) и в итоге: оптимизированный код + неоптимизированный = неоптимизированный код. Мартышкин труд в общем, больше не советуй таких умных мыслей :)

gh0stwizard ★★★★★
()

Можно ли как-то вот этак сделать в Perl или категорически нельзя?

И можно и нельзя. В классическом ООП перла это нельзя, т.к. нету нужных средств. С помощью костылей это возможно, смотри caller(), import и AUTOLOAD. Этот вариант называется хаком, обходом привычного хода вещей. Вместо этого придумали Moo.

Кстати, хранение всех собственных данных объекта в каком-нибудь громадном хэше

Как человек с определенным опытом в этом вопросе, могу сказать, что перл хорошо оптимизирован на работу с хэшами хэшей. Но у него есть свои лимиты вложенности.

все эти многоуровневые индексы куда менее эффективны

Индекс строится для каждой структуры (хэш, массив) отдельно и эффективны также как и без вложенности.

$ObjectData{refaddr $self}{'options'}{'user-defined'}{'var-a'}

Тут только проблема в цене разыменовывания. Если сделать по-классике, т.е. как в принято в Си, на котором написан перл:

my $hash_vars_a = $ObjectData{refaddr $self}{'options'}{'user-defined'}{'var-a'};

for (keys %$hash_vars_a) {
   my $value = $hash_vars_a->{$_};
   ...
}
То код будет также эффективно работать. Ибо перл работает с адресами, а не «путями» из первоначальной структуры. Ты можешь вайпнуть все остальное, оставив кусок структуры с адресом:
my $options = delete $ObjectData{refaddr $self}{'options'};
# cleanup
$ObjectData{refaddr $self} = ();
%ObjectData = ();
undef %ObjectData; # Non-necessary: called explicity because we want this right now.

простые переменные

Верно. И велосипедить хэш, хэш-функции? За тебя люди уже постарались и делают это на отлично.

P.S. Проблема перла (тикля в том числе) при работе с хэшами и массивами только одна: оптимистичное выделение памяти (никогда не возращается в ОС) и размер минимальной длины значения. Последнее означает, что массив из 1 млн. чисел в 32 байта будет куда больше, чем ты ожидаешь. Решено, через XS (модуль Bit:Vector).

gh0stwizard ★★★★★
()
Последнее исправление: gh0stwizard (всего исправлений: 1)
Ответ на: комментарий от gh0stwizard

Увы 95% модулей на CPAN совсем не оптимизированны (даже те, что написаны в XS) и в итоге: оптимизированный код + неоптимизированный = неоптимизированный код. Мартышкин труд в общем, больше не советуй таких умных мыслей :)

предлагаешь чтоб везде было неоптимизированный код + неоптимизированный код = неоптимизированный код? :)

Deleted
()
Ответ на: комментарий от Deleted

Нет, я не предлагаю. Это вывод из опыта. Если код действительно стоящий, то первое: он будет не на перле, а на си (xs) :) Второе: он рано или поздно уйдет в массы, а в массах обычно никто не смотрит на оптимизации. Зато! Твой код будет трудно-читаем. Сложен для модифицирования, вместо записи 1 строчки, придется менять код в 2-10 местах. Как итог, только умный оценит твой код, другие, более, скажем, адекватные, перепишут все в обычном стиле: том же класическом ООП перла. И правильно сделают: код уменьшится, станет легко-читаем и модифицировать сможет даже младенец.

Что делать? Писать сразу на XS, дабы не извращать язык (если реально оптимизируем). Итак слагают легенды: «один раз написал, ниразу не смог прочитать», «код на перле это вывод функции шифрования RSA» и т.п. За примерами далеко ходить не надо: смотрите как сделан Mojo (если пишем в Pure Perl и не хотим XS).

gh0stwizard ★★★★★
()
Последнее исправление: gh0stwizard (всего исправлений: 1)
Ответ на: комментарий от gh0stwizard

О, глянул твои теги, и там еще числится тикль. Скажи пожалуйста, как в перле создать многоверсионную либу, как в тикле? Чтоб одним дистрибутивом шла. Версия 1.0 - одно поведение методов, 2.0 - немного другое, «исправленное», или идеологически-разное. Может знаешь оптимальный какой-нибудь perl-way, чтоб не по стопам один в один...

Deleted
()
Ответ на: комментарий от Deleted

Скажи пожалуйста, как в перле создать многоверсионную либу, как в тикле?

Никак. Т.е. простой способ только через выставление путей в переменной PERL5_LIB. Либо, для совсем извращенцев: через use lib «mypath/to/version/XXX». По последнему пути даже придумали модуль local-lib. Этот модуль, скорее всего, то, что ты ищешь. Но его придумали не для твоей цели: для тестирования и сопровождения. Некоторые берут и используют его для развертывания. Но, такой вариант хорош, имхо, только для демонов. Для простых програм... буэ-э-э :)

Если уж совсем по-хацкерцки, то тоже что советовал здесь: perldoc -f caller [import, AUTOLOAD]. Просто потому, что для перла либа/модуль это прежде всего файл, а не его начинка. Чтобы что-то изменить в начинке в зависимости от внешних параметров, нужно менять файл.

gh0stwizard ★★★★★
()
Последнее исправление: gh0stwizard (всего исправлений: 1)
Ответ на: комментарий от gh0stwizard

Кстати, я к освещению замыкания в итоге и пришёл...

В общем работает всё как нужно - за исключением того факта, что если используешь замыкание, то в нём должны использоваться только такие же функции-замыкания. Пока я этого не понял, жутко мучался с тем фактом, что функции, вложенные в другие функции, даже если это была функция-замыкание, компилируются только один раз.

Я имею в виду вот такую проблему, например:

#!/usr/bin/perl
sub new {
 my $name=shift;
 return sub {
  sub sayHello {
   print "Welcome onboard, $name!!!\n"
  }
  print "$name, we are glad to see you!\nSo... how do you think, what do we want to tell you now?\nYes, you right!\n";
  sayHello
 }
}

my @f=map { new($_) } 'Alex','Mike';
$f[0]->();
print '=========',"\n";
$f[1]->();

Результатом будет не вполне очевидное:

Alex, we are glad to see you!
So... how do you think, what do we want to tell you now?
Yes, you right!
Welcome onboard, Alex!!!
=========
Mike, we are glad to see you!
So... how do you think, what do we want to tell you now?
Yes, you right!
Welcome onboard, Alex!!!

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

Используй не наименованные функции, а замыкания:

sub makeHappy {
  $name = $_[1]
  {
    'h' => sub { print "$name thanks man"},
    'q' => sub { print "k $name" },
    $_[0] => sub { print ";_; $name" }
  }->{$_[0]}
}

makeHappy('h', 'Mike')->();

anonymous
()
Ответ на: комментарий от anonymous

fix

#!/usr/bin/perl

use strict;
use warnings;

sub makeHappy {
    my $name = $_[1];
    {
	"$_[0]" => sub { print ";_; $name \n" },
	'h' => sub { print "$name thanks man \n"},
	'q' => sub { print "k $name \n" },
    }->{$_[0]};
}


my @happies =  map { makeHappy(@{$_}) }  [qw(h Mike)], [qw(q Lassy)], [qw(w wow)];

$_->() for @happies;

anonymous
()
Ответ на: комментарий от DRVTiny

Я бы на твоём месте, если perl-ОО в классическом исполнение так перечит, писал бы в high-order-perl стайле (http://hop.perl.plover.com/). Так как твоё ООП из палок и sub'ов не будет ложится в привычные механизмы ОО в perl и тем самым, вызывая mindfuck.

anonymous
()
Ответ на: комментарий от DRVTiny

Мне неясно, что тебе так полюбились замыкания. Классик:

package MONOLOG;
 
use strict;
 
sub new {
  my ( $class, $name ) = @_;
 
  my $self = bless { name => $name }, $class;
 
  $self->process();
 
  return $self;
}
 
sub name {
  return $_[0]->{'name'};
}
 
sub process {
  my ( $self ) = @_;
 
  my $name = $self->name();
 
  printf "%s, we are glad to see you!\nSo... how do you think, what do we want to tell you now?\nYes, you right!\n",
         $name;
  printf "Welcome onboard, %s!!!\n", $name;
 
  return $self;
}
 
 
package main;
 
use strict;
 
my $alex = MONOLOG->new('Alex');
my $mike = MONOLOG->new('Mike');

http://ideone.com/dOTBSr

Вывод так как ты хочешь:

Alex, we are glad to see you!
So... how do you think, what do we want to tell you now?
Yes, you right!
Welcome onboard, Alex!!!
Mike, we are glad to see you!
So... how do you think, what do we want to tell you now?
Yes, you right!
Welcome onboard, Mike!!!

Теперь допустим мы делаем фабрику, следовательно process должна быть абстракцией:

#!/usr/bin/perl
# your code goes here

package MONOLOG;

use strict;

sub new {
  my ( $class, $name ) = @_;
 
  my $self = bless { name => $name }, $class;
 
  $self->process();
 
  return $self;
}

sub name {
	return $_[0]->{'name'};
}

sub process {
	die "abstract";
}

package MONOLOG::Simple;

use strict;
use parent -norequire, 'MONOLOG';

sub process {
	my ( $self ) = @_;
	
	my $name = $self->name();
	
	printf "Welcome, %s!!!\n", $name;
	
	return $self;
}


package main;

use strict;

eval {
	my $abstract = MONOLOG->new('whatever');
};

print "As expected: $@" if ($@);

my $alex = MONOLOG::Simple->new('Alex');
my $mike = MONOLOG::Simple->new('Mike');
As expected: abstract at prog.pl line 23.
Welcome, Alex!!!
Welcome, Mike!!!

http://ideone.com/sBwfgt

gh0stwizard ★★★★★
()
Ответ на: комментарий от DRVTiny

Ну, анон уже сказал, имхо, так более читабельно:

sub new {
  my ( $name ) = @_;

  return sub {
    print "$name, we are glad to see you!\nSo... how do you think, what do we want to tell you now?\nYes, you right!\n";
    print "Welcome onboard, $name!!!\n";
  };
}

my @mysubs = map { &new("$_") } 'Alex','Mike';

$_->() for @mysubs;

http://ideone.com/jXpwYz

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

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

Замыкание позволяет именно так и делать: анонимная функция получает свой уникальный «слепок» переменных: хэши, массивы, скаляры - все они будут уникальны для каждой «благословлённой» анонимной функции-замыкания.

То есть я могу сделать вот так:

package My::Class;
my $lastCreatedObj;
sub new {
 my ($class,%Config)=@_;
 my %Props;
 unless ($lastCreatedObject) {
  foreach my $method ('debug') {
   *$method=sub :lvalue {
     my $self=ref($_[0]) eq 'My::Class'?shift:$lastCreatedObject;
     die 'You MUST create class instance (object) to use class methods!' unless $self;     
     $self->(@_)
   }
  }
 } 
 $lastCreatedObject=bless sub :lvalue {
  my $methodName=shift;
  my %methods=(
   'debug'=>sub :lvalue {
     $Config{'debug'}=shift if @_;
     return $Config{'debug'}
   },
   'default'=>sub :lvalue {
     my ($propName,$propVal)=@_;
     $Props{$propName}=$propVal if defined($propVal);
     return $Props{$propName};
   },
  )
  if ($methods{$methodName}) {
   $methods{$methodName}->(@_)
  } else {
   $methods{'default'}->($methodName,@_)
  }
 },$class;
}
Меня такой подход устраивает полностью за исключением того факта, что я теперь могу внутри своей clojure использовать только функции в стиле и духе функционального программирования: они будут обязаны принимать все необходимые параметры на вход и не могут использовать «глобальные» по отношению к ним переменные типа того же хэша %Config!

Вот от этого я и расстраиваюсь сильно :)

P.S. Извините за код без подсветки, пойду читать справочник по LORCODE'у

DRVTiny ★★★★★
() автор топика
Последнее исправление: DRVTiny (всего исправлений: 1)
Ответ на: комментарий от DRVTiny

и не могут использовать «глобальные» по отношению к ним переменные типа того же хэша %Config

Ээээ, если правильно распарсил, то передавай ссылку на объект :)


package My::Class;

sub new {
  my ( $class, $configuration ) = @_;

  if ( ref( $configuration ) ne 'HASH' ) {
    die "expected HASH, not " . ref( $configuration );
  }
  
  ...
}

package main;

my %Cfg = (
  # huge configuration lies there..
);

my $obj1 = My::Class->new( \%Cfg ); # <-- instead of copy hash, put reference to it

my $obj2 = My::Class->new( \%Cfg ); # both objects $obj1 & $obj2 are working with "global" configuration now

Можно запихнуть еще массу фишек и проверок для надежности, няшности. Логика, думая, ясна.

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

Всё как раз наоборот :)

Мне нужно, чтобы оба объекта использовали свою версию %Config!

И при этом чтобы внутри кода объектов я мог обращаться, например, к $Config{'debug'}, а не к $slf->{'config'}{'debug'}.

Ну или вместо $slf->{'a'} - просто к переменной $a.

DRVTiny ★★★★★
() автор топика
Ответ на: комментарий от DRVTiny

Ну или вместо $slf->{'a'} - просто к переменной $a.

Откажись вообще от Perl OO, в том числе bless. Все строй на функциях, замыканиях и переменных (скаляры, хэши, массивы).

gh0stwizard ★★★★★
()
Ответ на: комментарий от DRVTiny

:)

По-моему, я что-то не так понял и теперь ты не понимаешь о чем я. Из кода здесь я вижу, что все, что тебе нужно работает как надо. Я просто не понял от чего ты расстраиваешься.

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

Проблема возникает, когда мне нужно внутри clojure использовать какую-нибудь функцию, работающую с тем же «объект-специфичным» %Config'ом

Такую функцию приходится объявлять тоже как clojure наподобие $a=sub {} - иначе она будет работать почему-то не с тем %Config, который актуален для данного «объекта», а с тем %Config, который был инициализирован при первом вызове конструктора new. А хотелось бы вызывать функции не по ссылке, а просто по имени.

Хотя в принципе синтаксическая разница между

sub doSmth {
...
}
doSmth ("what2do")
И
my $doSmth=sub {
...
}
$doSmth->("what2do")

- не такая уж большая, и я уже думаю «смириться» с этим, поскольку иного выхода не вижу.

DRVTiny ★★★★★
() автор топика
Последнее исправление: DRVTiny (всего исправлений: 1)
Ответ на: комментарий от gh0stwizard

Если говорить о конечной цели всего этого, то в общем да, мне нужно, чтобы код объекта был процедурно-ориентированным, а интерфейс - объектным.

Из-за чего я вообще полез в эти дебри - мне нужно было, чтобы в одной программе существовало несколько инстансов одного класса, использующих каждый свой набор переменных. Задача была скопировать с одного Zabbix-сервера на другой юзеров с помощью Zabipi, а он у меня пока имеет процедурный интерфейс. Поскольку нельзя было переложить на пользователя обязанность передавать каждый раз некий «идентификатор» инстанса в явном виде (это было бы уж слишком нагло с моей стороны), я решил переписать этот API в объектном стиле, поскольку там идентификатор инстанса передаётся «магическим» способом, хотя магия эта и кривая немного: на самом деле нельзя сказать, что вызов $obj->something(...) существенно лучше простого something($obj,..)

DRVTiny ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.