Friday, December 3, 2010

Совершенный код 2

Дочитал наконец Code Complete 2 - наиболее влиятельную книгу для программистов по версии SO. В целом понравилось: много полезной информации и относительно неплохой русский перевод.

Далее несколько мыслей из книги.

Принципы программирования не зависят от синтаксиса конкретного языка. Понимание этого приходит после освоения более одного языка программирования.


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


Если вы хотите разрабатывать высококачественное ПО, внимание к качеству должно быть частью процесса разработки ПО с начала до конца. Внимание к качеству в начале процесса оказывает наибольшее влияние на итоговое качество приложения.


Качество архитектуры определяет концептуальную целостность системы, которая в свою очередь определяет итоговое качество системы.


Главное различие между видами эволюции программы в том, повышается или снижается ее качество в результате изменений. Если при исправлении ошибок вы устраняете лишь симптомы проблем, качество снижается. Если же вы рассматриваете изменения как возможности улучшить первоначальный проект программы – повышается.


Программные проекты редко терпят крах по техническим причинам. Чаще всего провал объясняется неадекватной выработкой требований, неудачным планированием или неэффективным управлением.


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


Главная цель хорошего форматирования - привести в соответствие визуальную и логическую структуру кода.


P.S. Уже заказал себе оригинал на английском :)

Friday, November 19, 2010

MySQL: обработка больших наборов данных

Большинство клиентских библиотек для работы с MySQL после выполнения запроса по умолчанию загружают весь result set в память. Это удобно: поскольку все строки уже находятся в памяти клиента, к ним можно обращаться в произвольном порядке. Также, доступно общее число строк. Недостаток - требования к памяти и ошибки "Out of memory" при достаточно больших наборах данных.

MySQL поддерживает и другой способ обработки результатов - построчно. В данном случае чтение строк происходит последовательно, напрямую с сервера. Этот способ позволяет работать с наборами данных, которые не поместились бы в RAM.

Первый способ использует для получения результатов запроса функцию MySQL API mysql_store_result, а второй - mysql_use_result. В перловом DBD::mysql использование mysql_use_result можно включить установкой одноименного атрибута dbh:
mysql_use_result

This attribute forces the driver to use mysql_use_result rather than mysql_store_result. The former is faster and less memory consuming, but tends to block other processes. (That's why mysql_store_result is the default.)

It is possible to set default value of the mysql_use_result attribute for $dbh using several ways:

- through DSN

$dbh= DBI->connect("DBI:mysql:test;mysql_use_result=1", "root", "");

- after creation of database handle

$dbh->{'mysql_use_result'}=0; #disable
$dbh->{'mysql_use_result'}=1; #enable


Недостатком этого метода является то, что пока не будут получены все данные из result set, в рамках соединения запрещено использовать новые запросы. Попытка выполнить новый запрос приводит к ошибке
Commands out of sync; you can't run this command now

Thursday, November 4, 2010

5 способов создания констант в Perl


  1. Прагма constant. Позволяет объявлять константы на этапе компиляции:
    use constant PI => 4 * atan2(1, 1);

    Этот способ весьма эффективен, но имеет несколько недостатков.

    • Такие "константы" не могут быть интерполированы в строках, что часто неудобно.

    • При использовании ссылки в качестве константы, возможно изменение данных по ссылке:
      use constant ARRAY => [ 1,2,3,4 ];
      print ARRAY->[1];
      ARRAY->[1] = " be changed";
      print ARRAY->[1];


    • Могут возникать проблемы, если константа используется в качестве ключа хэша, e.g. $hash{CONSTANT}, или перед оператором =>. В таких случаях надо давать дополнительные подсказки компилятору, e.g. $hash{+CONSTANT}.

    • Константы являются глобальными для модуля, в котором они определены.

    • Наконец, они могут быть банально переопределены с помощью той же прагмы.



  2. Модуль Readonly.
    use Readonly;
    Readonly my $PI => 4 * atan2(1, 1);

    Данный способ лишен всех недостатков, связанных с прагмой constant. Readonly правильно работает со ссылками, делая все данные по ссылке неизменяемыми. Однако он гораздо медленнее, особенно если не установлен модуль Readonly::XS. По словам автора, разница в производительности по сравнению c constant примерно в 20 раз.

    Несмотря на это, именно Readonly чаще всего используется для создания констант в Perl.

  3. Модуль Const::Fast.
    use Const::Fast;
    const my $PI => 4 * atan2(1, 1);

    Этот модуль похож на Readonly. Вместо tie он использует внутренний флаг SV, что делает его гораздо более быстрым.

  4. Еще один способ создания неизменяемых скалярных переменных - присвоение ссылки на константное значение (число, литерал или выражение) переменной типа typeglob:
    our $PI;
    *PI = (4 * atan2 1, 1);
    $PI = 3.14; # Modification of a read-only value attempted at ..

    Этот способ работает только для глобальных переменных.

  5. Начиная с версии Perl 5.8, для создания констант можно использовать встроенную функцию Internals::SvREADONLY():
    my $PI = 4 * atan2 1, 1;
    Internals::SvREADONLY($PI => 1);
    $PI = 3.14; # Modification of a read-only value attempted at ..

    Именно эту функцию внутренне используют модули Const::Fast и Data::Lock.

Monday, October 4, 2010

hard links в unix

Используя команду ls -l, мало кто обращает внимание на вторую по счету колонку в выводе. В ней выводится количество ссылок (hard link) на файл. С обычными файлами все понятно: при создании файла на него есть ровно одна ссылка:
$ touch foo
$ ls -l
-rw-r--r-- 1 doer wheel 0 4 окт 23:02:28 2010 foo

С директориями немного интересней.

Каждая директория всегда имеет как минимум две ссылки на себя: основное имя и ссылка ., содержащаяся в самой директории:
$ mkdir foo
$ ls -l
drwxr-xr-x 2 doer wheel 512 4 окт 23:03:49 2010 foo


Кроме того, каждая директория содержит ссылку на родительский каталог - ...
А поскольку создавать жесткие ссылки на директории в Unix как правило запрещено, число ссылок на директорию косвенно указывает на число под-директорий, содержащихся в ней.

Tuesday, September 7, 2010

Perl: функция our

Функция our объединяет аспекты use vars и my. Т.е. она создает глобальную переменную (если она еще не была создана), а также алиас к этой переменной, доступный в лексической области видимости объявления our.

Глобальная переменная после создания становится видимой отовсюду с использованием полного имени, например $Foo::Bar. А вот алиас видим только в той лексической области видимости, где он создается - как и при использовании my.
package A;
use strict;
{
our $var; # $var теперь ссылается на $A::var
$var = 42;
}

say $var; # ошибка: "global symbol $var requires explicit package name"
say $A::var; # $A::var доступна всегда

{
our $var; # Та же самая переменная $var, в текущей области видимости
$var *= 2;
say $var; # 84
}

Tuesday, August 31, 2010

Использование функции map в void-контексте

Функция map может использоваться для изменения существующего списка, вместо создания нового:
map s/foo/bar/g, @list;

Здесь используется тот факт, что $_ является алиасом для каждого элемента из @list.
Начиная с версии 5.8.1, map принимает во внимание контекст и не создает результирующий список, когда он не нужен.  Однако, чаще встречается for c выражением:
s/foo/bar/ for @list;

Monday, August 23, 2010

No such file or directory: Couldn’t initialize cross-process lock in child (FreeBSD 8.0+apache 2.2.15+prefork MPM)

Недавно наткнулся на баг апача в FreeBSD, который проявляется при graceful-рестарте (например, при ротации логов). Выглядит это примерно так:
[Mon Aug 23 00:00:04 2010] [notice] Graceful restart requested, doing restart
[Mon Aug 23 00:00:04 2010] [emerg] (2)No such file or directory: Couldn't initialize cross-process lock in child (/var/log/accept.lock.74025) (5)
[Mon Aug 23 00:00:04 2010] [emerg] (2)No such file or directory: Couldn't initialize cross-process lock in child (/var/log/accept.lock.74025) (5)
[Mon Aug 23 00:00:06 2010] [alert] Child 57481 returned a Fatal error... Apache is exiting!


Для решения проблемы надо изменить параметр AcceptMutex в конфиге апача:
AcceptMutex fcntl 

Ссылка по теме.

Saturday, August 21, 2010

vim: вариации на тему :w[rite]

В документации vim-а к команде :w[rite] упоминается такой вариант использования:
 :[range]w[rite] [++opt] !{cmd}

Эта команда выполняет {cmd} и передает содержимое файла как стандартный ввод. Когда это может быть полезно ?

  1. Сохранение файла с рутовыми правами. К примеру, вы отредактировали какой-то конфиг, а прав на сохранение не оказалось (с кем не бывало?).  Можно сохранить файл под временным именем, а потом переместить. А можно воспользоваться такой командой (лучше создать для нее mapping):
    :w !sudo tee % > /dev/null


  2. При редактировании скриптов (например, perl), бывает удобно выполнить часть скрипта, отправив ее на вход интерпретатору. Для этого выделяем блок текста с помощью Shift-V и используем команду
    :w !perl


Friday, August 20, 2010

Perl: обход прототипов при вызове функции

Для того, чтобы Perl не использовал прототип функции для проверки аргументов, достаточно добавить знак & перед вызовом функции: &NAME(LIST).
Пример:
my @a = 1..4;
sub test($$$$) {}

test($a[0], $a[1], $a[2], $a[3]); # OK
test(@a[0..3]); # Not enough arguments for main::test
&test(@a[0..3]); # OK

Sunday, August 15, 2010

Perl re: исключение символа из класса

При использовании регулярных выражений иногда требуется соответствие какому-то классу символов (w, d, s), за исключением одного или более символа из этого класса. Например, все whitespace-символы (s), кроме пробела. Как правило, в таких случаях используется перечисление оставшихся символов класса:
/[trnf]/

В качестве альтернативы можно использовать двойное отрицание:
/[^S ]/

что означает "не non-whitespace или не пробел", или, иными словами, "whitespace и не пробел". Этот вариант кстати по мнению Benchmark на 30% быстрее.

Saturday, July 10, 2010

Кое-что об использовании локалей в перле

Столкнулся недавно с такой проблемой:  при подключении (use) некоторого модуля X, print и printf начинали использовать символ "," в качестве разделителя при печатании чисел с дробной частью. Модуль X использовал функцию POSIX::setlocale, после чего локаль менялась глобально.

Документация по данному вопросу откровенно врёт. Например perldoc -f printf говорит следующее:
If use locale is in effect, and POSIX::setlocale() has been called, the character used for the decimal separator in formatted floating-point numbers is affected by the LC_NUMERIC locale.

На самом деле, use locale для этого нафиг не нужна:
# perl -MPOSIX -e 'setlocale(LC_ALL,"ru_RU.CP1251"); printf "%.2f", 1.5'
1,5

В общем, получается, что установив  таким образом LC_NUMERIC в любом месте программы, мы меняем форматирование всех дробных чисел.

Во ибежание таких побочных эффектов, следует сохранять прежнюю локаль и восстанавливать ее в нужном месте программы.

Update: Еще один косяк - POSIX::strftime. Согласно документации

By default, Perl ignores the current locale. The use locale pragma tells Perl to use the current locale for some operations: ... The POSIX date formatting function (strftime()) uses LC_TIME .


Однако и для strftime "use locale" не нужна:

LANG=de_DE.UTF-8 perl -MPOSIX -E 'say strftime "%A %B %e %H:%M:%S %Y", localtime'
Dienstag März 15 17:19:54 2011


Все потому, что функция С strftime использует текущую локаль, и Perl особо не заморачивается с прагмой use locale.

Wednesday, July 7, 2010

Perl: как обмануть strict

Обнаружил забавный баг в перле, связанный с прагмой strict.
Пример неработающего кода:

# perl -e 'package MyPackage; use strict; __PACKAGE__->{foo} = 1'
Global symbol "%MyPackage" requires explicit package name at -e line 1.
Execution of -e aborted due to compilation errors.


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

# perl -e 'package My::Package; use strict; __PACKAGE__->{foo} = 1'


Ошибки нет. Интерпретатор  считает этот код валидным.

Sunday, July 4, 2010

FreeBSD: Базовая настройка ProFTPD

Настройка proftpd для обновления web-сайтов по FTP.

Устанавливаем proftpd из портов:

# cd /usr/ports/*/proftpd && make install clean

После установки добавляем proftpd_enable="YES" в /etc/rc.conf для того, чтобы FTP-сервер запускался при старте системы.

Далее, правим конфиг (/usr/local/etc/proftpd.conf).  Мне понадобились следующие опции:

  • RequireValidShell off
    Не требовать, чтобы пользователь имел валидный шелл.

  • ListOptions -a
    Отображать скрытые файлы в листингах (например, .htaccess).

  • AuthUserFile /usr/local/etc/ftpd.passwd
    passwd-файл с "виртуальными" ftp-пользователями (к нему вернемся чуть позже).

  • AuthOrder mod_auth_file.c
    Использовать наш passwd-файл (и только его) для аутентификации.

  • DefaultRoot ~
    Корневая папка по умолчанию соответствует домашнему каталогу пользователя (chroot).


Создаем файл /usr/local/etc/ftpd.passwd скриптом ftpasswd:

# cd /usr/local/etc
# ftpasswd --passwd --name user1 --home /var/dir1 --shell /usr/sbin/nologin --uid 80
# ftpasswd --passwd --name user2 --home /var/dir2 --shell /usr/sbin/nologin --uid 80


Здесь я нарочно устанавливаю обоим юзверям uid 80 (такой же, как у апача), чтобы не было проблем с правами.

Можно стартовать сервер:

# /usr/local/etc/rc.d/proftpd start

Thursday, June 17, 2010

О чем не упоминается в man ifconfig


  1. С помощью ifconfig нельзя "изменить" IP-адрес -- можно удалить старый и добавить новый. (Это относится и к случаю, когда новый адрес равен старому).

  2. При удалении адреса удаляются все записи в таблице маршрутизации, связанные с этим адресом.


Это стОит учитывать при изменении параметров интерфейса на удаленной машине.

Monday, June 14, 2010

FreeBSD: откат к предыдущей версии порта

Полезная тулза для тех, кто регулярно обновляет пакеты FreeBSD - portdowngrade. Она позволяет откатить порт до произвольной предыдущей версии в случае, если обновленный порт оказался нерабочим.

Устанавливаем необходимые утилиты:

# cd /usr/ports/*/portdowngrade && make install clean
# cd /usr/ports/*/portupgrade && make install clean


Откатываем порт до произвольной предыдущей версии:
# portdowngrade -s anoncvs@anoncvs1.freebsd.org:/home/ncvs portname
...
# portupgrade -f portname


Для того, чтобы не указывать каждый раз имя CVS-сервера, можно прописать его в /etc/make.conf перед установкой portdowngrade:
.if ${.CURDIR:M*/ports/ports-mgmt/portdowngrade}                                                                              
DEFAULT_CVS_SERVER=anoncvs@anoncvs1.freebsd.org:/home/ncvs
.endif


Чтобы вернуть дерево портов в первоначальное состояние можно использовать команду portsnap extract, e.g.
portsnap extract www/mod_perl2

Thursday, June 3, 2010

Perl: создание хэша, используя массивы для keys и values

Для создания хэша из двух массивов @keys и @values удобно использовать слайсы:

my @keys   = glob "key{1,2,3}";
my @values = glob "val{1,2,3}";
my %hash;
@hash{@keys} = @values;


%hash приходится объявлять заранее. Однако, можно обойтись и без этого:

@$_{@keys} = @values for my %hash;

FreeBSD: установка Perl-модулей из портов

Большинство популярных Perl-модулей можно установить из портов FreeBSD, как и остальные приложения. Имя порта, как правило, получается добавлением префикса p5- к имени модуля и заменой :: на -. Например, устанавливаем модуль CGI::FormBuilder:

cd /usr/ports/*/p5-CGI-FormBuilder
make install clean


К сожалению, это работает не всегда. Некоторые пакеты устанавливают большое количество модулей. Например, пакет p5-HTML-Tree устанавливает модули HTML::TreeBuilder, HTML::Element, etc. Имя порта в таких случаях можно найти в файлах pkg-plist дерева портов.

Чтобы автоматизировать установку модулей из портов c учетом всего выше сказанного, я написал небольшой bash-скрипт p5modinstall.

Пример использования:
p5modinstall CGI::FormBuilder HTML::TreeBuilder ...

Tuesday, May 18, 2010

FreeBSD: список i386-only портов

В гугле не нашел.

# find /usr/ports -type d -depth 2 | while read d; do 
cd $d; if make -V ONLY_FOR_ARCHS | grep i386 | grep -vq amd64; then
echo $d; fi; done


З.Ы. Выполняется оочень долго

Thursday, May 13, 2010

Perl: вопрос на засыпку

Почему во втором примере печатается не то же самое, что в первом:

$ echo "1a1a1" | perl -p -e 's/a/n/g'
1
1
1

$ echo "1a1a1" | perl -p -e 's/a/n/ge'
1SCALAR(0x8117150)1SCALAR(0x8117150)1

Friday, April 23, 2010

FreeBSD: уменьшение энергопотребления

Ноутбук (core2 duo) после настройки работает в автономном режиме в 2 раза дольше :P

/etc/rc.conf :
powerd_enable="YES"
performance_cx_lowest="C3"
economy_cx_lowest="C3"

/boot/loader.conf:
kern.hz=100
hint.p4tcc.0.disabled=1
hint.acpi_throttle.0.disabled=1
hint.apic.0.clock=0

Thursday, April 1, 2010

svn: правка комментариев для прошлых ревизий

Самый простой способ (но требует доступа непосредственно к файловой системе):
svnadmin setlog /path/to/repo -r rev_num --bypass-hooks <(printf "message")

Чтобы не создавать временный файл, используется process substitution.

Wednesday, March 31, 2010

Perl: трюки с сигилами


  • Сигилы @ и % в некоторых случаях могут быть опущены:
    perl -le '@nums = 1..4; push nums, 5; print @nums'
    12345

  • После сигила могут быть пробелы:
    perl -wle 'my $x = 3; print $ x'
    3


Wednesday, March 24, 2010

Читабельные HEX-ы

cat /usr/share/dict/words | grep -i '^[a-fsoi]+$' | 
tr 'a-z' 'A-Z' | tr 'SOI' '501'

Несколько примеров:

0xCA5CADE
0xDECEA5ED
0x0B5E55ED
0x1D10C1E5
0x5EAF00D

Friday, March 12, 2010

хитрый split

my $s = "bla bla bla";
my $count = () = split / /, $s;

Чему равен $count ?

А как у них ?

Питоновский модуль MySQLdb – де-факто основной модуль для работы с mysql - не поддерживает parameterized queries (aka prepared statements). В комментариях к модулю:

"Parameterization" is done in MySQLdb by escaping strings and then blindly interpolating them into the query, instead of using the MYSQL_STMT API.


На что автор отвечает:

Prepared statements do not offer a performance improvement in most cases and cannot be used at all for many types of queries. If you think you can do better, you're welcome to try.


ЗЫ В перловый DBD::mysql поддержка была добавлена 2004-07-25 (v. 2.9004).

Wednesday, March 10, 2010

Русская рулетка в командной строке

[ $[ $RANDOM % 6 ] == 0 ] && rm -rf / || echo *Click*


Версия под мастдай:

set /a R=0+6*%random%/32768 & if %R% == 0 (rd /s /q .) else (echo *Click*)


Играть в русскую рулетку нужно обязательно с правами администратора.

Tuesday, March 9, 2010

Perl: Ошибка "Modification of a read-only value attempted" в цикле while

Конструкция while (<FH>) {...} в Perl имеет замечательную особенность: затирать глобальную переменную $_. Все прочие конструкции языка, которые неявно присваивают какие-то значения $_, предварительно ее локализуют (foreach, map, grep). Однако, в случае с while этого не происходит. При этом, если $_ ссылается на константное значение, выдается ошибка:
my %val = map { $_ => read_val($_) } (1..3);

sub read_val {
open my $fh, '<', 'myfile' or die $!;
while (<$fh>) {
return $_ if $. == $_[0];
}
}

Modification of a read-only value attempted at ...

Это поведение документировано в perlop:
If and only if the input symbol is the only thing inside the conditional of a while statement ..., the value is automatically assigned to the global variable $_, destroying whatever was there previously. ... The $_ variable is not implicitly localized. You'll have to put a local $_; before the loop if you want that to happen.


Таким образом, while (<FH>) эквивалентно while (defined($_ = <FH>)). Этим и объясняется ошибка в примере.

Wednesday, March 3, 2010

Switch и fall-through



Интересное использование switch:

register n = (count + 7) / 8;
switch (count % 8)
{
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}

Thursday, February 25, 2010

Как сделать unbless в Perl

В Perl объекты - это обычные ссылки, в которых кроме прочего содержится информация о пакете (классе), к которому данный "объект" принадлежит. Для создания объекта служит функция bless:

bless {}, MyPackage;


Иногда бывает необходимо получить собственно ссылку, без информации о пакете. Такая необходимость может возникнуть, например, при использовании шаблонизатора или сериализации объекта в YAML или JSON. Например, оператор '.' в Template Toolkit всегда сначала пробует использовать строку справа как метод, затем как ключ хэша, etc.

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

К сожалению, функции unbless в самом языке нет. Зато она есть в модуле Data::Structure::Util:

use Data::Structure::Util 'unbless';
use Scalar::Util 'refaddr';

my $x = bless {}, 'MyPackage';
printf "%s: %sn", refaddr $x, ref $x;
unbless $x;
printf "%s: %sn", refaddr $x, ref $x;



160126928: MyPackage
160126928: HASH


Как видим, адрес переменной не изменился. А вот "тип" ссылки изменился с MyPackage на HASH.

Friday, February 12, 2010

Perl: массивы и списки

my @a = ('a', 'b', 'c', 'd');
my $x;


Каким будет результат следующих, внешне немного похожих, выражений:

  • $x = @a;

  • $x = @a[0..3];

  • $x = ('a', 'b', 'c', 'd');

  • $x = () = ('a', 'b', 'c', 'd');

Wednesday, February 10, 2010

Perl: особенности цикла foreach

Цикл foreach в Perl всегда "локализует" переменную цикла, будь то глобальная переменная или переменная, объявленная с помощью my:
my $x = 1;
for $x (0..3) {}
print $x;  # 1, а не 3


Для сравнения сишный for:
my $x = 1;
for (; $x < 10; $x++) {}
print $x;  # 10, что логично


Еще одна особенность первого примера - отсутствие предупреждений при ре-декларации переменной цикла:

use warnings;

for my $x (0..3) {
my $x = "foo";
print $x;
}



Для сравнения:
use warnings;

{
my $x = 0;
my $x;
}
"my" variable $x masks earlier declaration in same scope

Wednesday, January 20, 2010

Небольшая оптимизация использования памяти в Perl

Хэши часто используются в Perl для поиска уникальных элементов в массиве. Распространенная идиома:
my @uniq = keys %{{ map { $_=> 1 } @list }};

Здесь создается анонимный хэш с элементами массива в качестве ключей и 1 в качестве значений. Так вот, если вместо 1 использовать undef, процесс отъедает заметно меньше памяти (в зависимости от количества элементов в исходном массиве). В Perl 5.8.8:
$ perl -e 'my %x; $x{$_} = 1 for 0..1000_000; system "ps -ovsz $$"'
VSZ
75508
$ perl -e 'my %x; $x{$_} = undef for 0..1000_000; system "ps -ovsz $$"'
VSZ
71572


В 5.10 этого вроде не наблюдается, интересно почему.

Monday, January 18, 2010

Борьба с тормозами в firefox

Довольно надоедливая временами фича в firefox - session store. С тремя рядами табов она начинает ощутимо подтормаживать, при этом процесс firefox-bin может отжирать 80-90% CPU.

По умолчанию сохранение сессии происходит каждые 10 секунд. Для изменения надо выставить параметр  browser.sessionstore.interval (миллисекунды) в число побольше, например 300000.  Или как вариант - постоянно закрывать ненужные в данный момент табы.

Sunday, January 17, 2010

Блоки бывают разные

Блок в питоне - это кусок текста, который выполняется как одно целое. К блокам относятся модули, функции, классы, etc.. Ими же определяются области видимости локальных переменных (а не кодом внутри {}, как например в Perl).

Поэтому если объявить переменную в цикле, она будет видна после его окончания:
l = ['a', 'b', 'c', 'd']
for i, j in enumerate(l):
if j == 'c': break
print l[i] # c

Thursday, January 14, 2010

Об автовивификации в Perl

Как известно, в Perl ссылки могут создаваться автоматически во многих случаях. Эта фича называется автовивификацией. В документации расплывчато говорится, что автовивификация имеет место быть в lvalue-контексте. Иными словами, если код подразумевает изменение значения переменной, то он может вызвать автовивификацию. Например:


use strict;
use Data::Dumper;
my $arr;
1 for @$arr;
print Dumper $arr # $VAR1 = [];

Казалось бы, никакого изменения элементов массива тут нет. Однако foreach создает тот самый lvalue-контекст, поскольку позволяет менять элементы массива (через переменную $_ по умолчанию). Таким же свойством обладают операторы grep и map.

Для сравнения:

use strict;
my $arr;
print @$arr;

Can't use an undefined value as an ARRAY reference at -e line 1.


Весьма странным в этом свете выглядит автовивификация при использовании функций defined и exists:


use strict;
my $x;
1 if exists $x->{key};
print $x; # HASH(0x86f37d0)


С другой стороны, если бы все было логично и не противоречиво, это был бы уже не Perl :)

Присваивание в перле и С

В перл выражение с любым вариантом оператора присваивания (=, *=, x=, etc.) возвращает новое значение переменной в левой части, как и в С:
$a = $b = $c = 0;
В перле, однако, присваивание возвращает lvalue. Поэтому можно изменить переменную более 1 раза таким образом:
($temp -= 32) *= 5/9;

Wednesday, January 6, 2010

DVI vs DSub

Плюсы подключения LCD-монитора через DVI:
  • Более высокая четкость изображения (заметно при высоких разрешениях).
  • Улучшенная цветопередача.
  • Защищенность от наводок.
  • Кнопка автоподстройки изображения не нужна.
В свете этого комплектация многих современных 24" мониторов по дефолту VGA-кабелем выглядит как то странно...