yorool_gui: (Default)
Michael Ilyin ([personal profile] yorool_gui) wrote2005-03-14 05:10 pm

о Perl

Перл замечательный язык, когда на нем пишу Я. Когда на нем пишут другие -- это кошмар. И подозреваю, что это взаимно.

use strict;
...
no strict 'refs';
...
$self->{LABELS}->{$title} = $3;
$self->{LABELS}->{$title}->{NUM} = $num++;

Это работатет. Но я не понимаю, ради чего надо так извращаться. Это не тот Перл, на котором пишу я. На моем Перле ref $self->{LABELS}->{$title} будет либо SCALAR, либо HASH, но никак не то и другое одновременно. А вот на Перле этого человека в $self->{LABELS}->{$title} хранятся сразу два значения и ему это удобно. Но это другой язык.

[identity profile] blacklion.livejournal.com 2005-03-14 02:16 pm (UTC)(link)
А я бы за другое убил -- за no strict 'refs';. Т.е. я просто отказываюсь понимать этот код. Сначала присваеаыем скалярь, а потом обращаемся к нему как к hash ref! Нет, я понимаю, как оно работает, но за любоею no strict (включая LABELS/NUM без кавычек) -- убивать.

[identity profile] sorhed.livejournal.com 2005-03-14 02:21 pm (UTC)(link)
У меня в одном месте no strict таки пользуется. Но я его уберу, если вы скажете, как можно без no strict refs обратиться к $AUTOLOAD :)

[identity profile] blacklion.livejournal.com 2005-03-14 02:23 pm (UTC)(link)
Да, это, пожалуй, единственный пример... Но тут явно не тот случай.

[identity profile] sorhed.livejournal.com 2005-03-14 02:27 pm (UTC)(link)
Ну, не только. Иногда (например, в коде одной извращённой штуки, которая использует собственную нестандартную модель наследования) бывают нужны symbolic references. Случаи, конечно, единичные. Но бывают.

(хотя, конечно, всё равно было бы неплохо, чтобы strict шёл по дефолту, а извращенцы вроде меня использовали бы no strict в специально отведённых местах).

[identity profile] blacklion.livejournal.com 2005-03-14 02:29 pm (UTC)(link)
(например, в коде одной извращённой штуки, которая использует собственную нестандартную модель наследования)
А вот какова необходимость в том, что бы она была такая ивзращенная?

[identity profile] sorhed.livejournal.com 2005-03-14 02:32 pm (UTC)(link)
Очень просто.
Где-то в недрах perldoc perlobj сказано, что если менять @ISA динамически где ни попадя, то ничего хорошего из этого не выйдет, так как оно там кэшируется. А мне как раз надо было динамически. Чтобы если девелопер захотел в живой системе созданный объект унаследовать от чего-нибудь ещё — то нет проблем.

[identity profile] blacklion.livejournal.com 2005-03-14 02:37 pm (UTC)(link)
А может лучше тогда переписать на python? :)
Вообще, плохо понимаю, зачем такое может понадобится и почему тогда это не реализовать через AUTOLOAD в виде модуля Class::DynamicInheritance какого-нибудь, от которого наследоватьв се такие классы...

[identity profile] sorhed.livejournal.com 2005-03-14 02:40 pm (UTC)(link)
Да я так почти и сделал.
Ну, в общем, вот о чём я говорю:

sub AUTOLOAD {
    my ($this) = @_;
    my $method_name = $AUTOLOAD;
    $method_name =~ s/^(.*):://;
    my $class_name = $1;
    $class_name =~ s/^(.*):://;
    my $package_name = $1;
    my $method = $this->get_method($method_name, $class_name);
    if ($method) {
        my $code = $method->{code};
        my $result = eval ($code);
        if ($@) { $this->error($@); }
        return $result; 
    } else {
        $this->error("Method $method_name for $class_name is not found.");
    }
}

sub get_method {
    my ($this, $method_name, $class_name) = @_;
    my $class = $this->{STORAGE}->get_class($class_name);
    my $class_id = $class->{class_id};
    my $method = $this->{STORAGE}->get_object(-name => $method_name,
                                      -class => 'Method', 
                                      -of_class => $class_id);
    if ($method) {
        return $method;
    } else {
        if ($class_name ne 'Object') {
            my $parent_class_id = $class->{parent};
            my $parent_class_name = 
                    $this->{STORAGE}->get_class($parent_class_id)->{name};
            return $this->get_method($method_name, $parent_class_name);
        } else {
            return undef;
        }
    }     
}

[identity profile] blacklion.livejournal.com 2005-03-14 02:46 pm (UTC)(link)
Бррр... Не вижу здесь не-стриктных референсов... Хотя eval($code) не очень понял зачем нужно, почему не $code(). Или там оно действительно строкой хранится?

[identity profile] sorhed.livejournal.com 2005-03-14 02:48 pm (UTC)(link)
Строкой. Из базы же достаётся.
А нестриктные референсы я всё-таки убрал, оказывается :) Блин, вот что значит три месяца в код не заглядывать.

[identity profile] blacklion.livejournal.com 2005-03-14 02:54 pm (UTC)(link)
А, ну из базы -- тогда да :) Это, как ты понимаешь, неочевидно из этого куска кода.

Хотя, производительность так должна страдать...

[identity profile] sorhed.livejournal.com 2005-03-14 02:55 pm (UTC)(link)
Есессно. Но Cache::Memcached никто не отменял.

[identity profile] blacklion.livejournal.com 2005-03-14 02:59 pm (UTC)(link)
Это ничем не поможет тормознутости eval "code"; или ты про кеширование результатов?

[identity profile] sorhed.livejournal.com 2005-03-14 03:00 pm (UTC)(link)
И того, и другого, и можно без хлеба а ещё я где-то слышал, что после эвала можно просто хранить ссылки на code references, только не знаю пока ещё, как :)

[identity profile] blacklion.livejournal.com 2005-03-14 03:09 pm (UTC)(link)
Вот последнее очень интересно. В JavaScript я просто скажу

var code = new Function( "some code; goes; here;" );

А про Perl -- Я как раз только что думал, как бы получить CodeV из eval'а... Вот так, сходу, способа не вижу... Т.е. вижу, но кривой до невозможности:

sub getCode
{
  my $code = $_[0];
  local *F;
  my $name = sprintf( "__getCode_unique_name_0x%08x_%s", $$, md5_hex($code) );
  open(F, "> /var/tmp/$$.pl");
  print F "sub ", $name, " { ";
  print F $code;
  print F "}";
  close(F);
  require "/var/tmp/$$.pl";
###
# DAMN!
  {
    no strict 'ref';
    $code = \&{$name};
  }
###
  unlink("/var/tmp/$$.pl");
  return $code;
}

Но ведь крииииво... И будет ли работать... Ччерт, давно на перле не писал...

[identity profile] sorhed.livejournal.com 2005-03-14 03:14 pm (UTC)(link)
В общем, если нужен источник вдохновения — рекомендую зайти на www.everydevel.com и скачать оттуда Everything Core (на котором, кстати, построен всеми нами любимый perlmonks.org). Я лично уже года два тягаю оттуда идеи :)

[identity profile] blacklion.livejournal.com 2005-03-14 03:19 pm (UTC)(link)
Так не интересно :)

[identity profile] blacklion.livejournal.com 2005-03-14 03:25 pm (UTC)(link)
ХА! Все проще! Прочел perldoc -f do внимательно (придя оттуда из perldoc -f require) и родил слкедюущую работающую конструкцию:


my $codeRef = eval "sub { $codeStr } ";

ВСЕ! Работает!

[identity profile] sorhed.livejournal.com 2005-03-14 03:27 pm (UTC)(link)
Гы, логично :)

[identity profile] co108.livejournal.com 2005-03-15 08:28 am (UTC)(link)
ой, а что вы за гарево-погарево тут делаете если не секрет? пишите перл++ на перле? :))

[identity profile] sorhed.livejournal.com 2005-03-15 11:27 am (UTC)(link)
Хуже. Smalltalk (точнее, Gemstone/S) на перле :)

[identity profile] sorhed.livejournal.com 2005-03-14 02:30 pm (UTC)(link)
Кстати, а за такое тоже убивают? :)

$possibly_unititalized ||= 'default_value';

[identity profile] blacklion.livejournal.com 2005-03-14 02:32 pm (UTC)(link)
Нет, IMHO. Это классический паттерн, вроде "*p++ = *q++;" в C. т.е. хакерство, но уже ставшее идиомой языка.

[identity profile] asd.livejournal.com 2005-03-14 02:22 pm (UTC)(link)
Всегда в начале скрипта писать:

use strict;
use utf8;
use warnings FATAL => 'uninitialized';


Это спасает от безумного кода :)

[identity profile] blacklion.livejournal.com 2005-03-14 02:22 pm (UTC)(link)
Именно.

[identity profile] yorool-gui.livejournal.com 2005-03-14 02:26 pm (UTC)(link)
Как раз и LABELS и NUM без кавычек отлично работает и при полном use strict. Я сам этим постоянно пользуюсь -- никаких проблем это не порождает, просто syntax sugar.
А вот no strict 'refs' -- это да. Я около часа тоже этот код понимать просто отказывался, тем более что no strict 'refs' было не сразу под use strict, а пятью строчками ниже, куда я сначала не поглядел.
Я, кстати, так толком и не пониямаю, как это работает. Не, я помню что-то про хитрые структуры, в которых хранятся перловые переменные и догадываюсь, что они просто хранят там два значения для разных типов. Но что вернет ref на такую переменную -- не понимаю.

[identity profile] blacklion.livejournal.com 2005-03-14 02:28 pm (UTC)(link)
ref -- ссылку на скаляр. А если мы обращаемся к нему как к хэшу, оно ищет, нету ли хэша с таким именем.

А вот без кавычек -- да, работает всегда. Но все равно очень не люблю. Потому что для меня идентификатор без типа в перле -- это однозначно константа (use constant { LABEL => 1, NUM => 2 };)

[identity profile] yorool-gui.livejournal.com 2005-03-14 02:51 pm (UTC)(link)
именно это я и имел в виду в исходном посте, насчет взаимно-кошмарного кода :-)

[identity profile] sorhed.livejournal.com 2005-03-14 02:56 pm (UTC)(link)
Ну, кстати, вы же не будете утверждать, что $hashref->{some_key} — это однозначное зло? :) Мне всегда было лень писать $hashref->{'some_key'}, тем более, и strict смотрит на это сквозь пальцы.

[identity profile] blacklion.livejournal.com 2005-03-14 02:59 pm (UTC)(link)
Однозначного зла вовсе нет :)

Да, это минорное зло. Я уже привык в чужом коде. Но сам не ленюсь :)

[identity profile] yorool-gui.livejournal.com 2005-03-14 04:35 pm (UTC)(link)
Блин, я только сейчас разобрался, что же там происходит. Там же глобальные переменные засирались как из гамномета, причем если попадались одинаковые значения, то они и отображались на одну и ту же переменную, отчего происходил Реальный Геморрой. Теперь мне все ясно, а исходный пост признается ересью.

[identity profile] asd.livejournal.com 2005-03-14 02:19 pm (UTC)(link)
С большой вероятностью, это зависит от размера проекта. Я писал довольно объёмные перловые модули, и ничего -- люди нормально понимали.

Но там без экстремизма было.