четверг, 1 апреля 2010 г.

Мог бы быть вопрос номер 3 на понимание Perl ...

... если бы я сам понимал что тут происходит
perl -e 'my $i=5; print(++$i + ++$i)' #  почему тут 14, а не 13 ???


perl -e 'my $i=5; print(sub{++$i}->() + sub{++$i}->())' #   тут все нормально - выдает 13



perl -e 'my $i=5; print( $i++ + $i++)' # и так нормально - выдает 11



14 коммент.:

Анонимный комментирует...

А что тут понимать?
В С подобное выполнить не пробовали?

zhdinar комментирует...

my $i = 5;
$i = $i++;
print $i; # выводит 5 а не 6, как вроде должно было быть

Анонимный комментирует...

Думаю что тут происходит так (дело в приоритетах)
сначала делается первый ++$i откуда получим $i=6 потом делатся второй раз ++$i откуда получим $i=7, а потом складываем два слагаемых в которых к этому времени уже $i=7

Анонимный комментирует...

> zhdinar комментирует...
> my $i = 5;
> $i = $i++;
> print $i; # выводит 5 а не 6, как вроде должно было быть

Что-то вы путаете, уважаемый. $i++ - постфиксная форма записи, и наращивание переменной выполняется после выполнения прочих операций, т.е. в данном случае операции print.

Анонимный комментирует...

> т.е. в данном случае операции print.

Пардон, попутал. Надо читать:"т.е. в данном случае операции сложения".

Переменной $i присваивается значение $i (т.е. 5), затем "старая" переменная увеличивается на 1, а потом уничтожается, т.к. над ней уже не производится никаких операций. Над "новой" $i больше никаких операций не производится, поэтому она и остаётся равной 5.

koorchik комментирует...

>А что тут понимать?
>В С подобное выполнить не пробовали?
Не пробовал

>Думаю что тут происходит так (дело в приоритетах)
Я с Вами полностью согласен, других вариантов особо и не вижу. Думаю, что это оптимизация для более быстрого выполнения. Perl не запоминает "6", а просто берет ее с переменной $i.
( Хотя по идее должно быть так:
Сначала вычисляется левый аргумент - инкремент на 1, а затем возврат "6". Потом вычисляется правый аргумент(полностью аналогично) - получаем 7. 6+7=13 )

Но меня смущает тот факт, что с таким примером:
perl -e 'my $i=5; print( $i++ + $i++)'
такого не происходит.
Когда Perl доходит до операции сложения, то $i уже равняется "6". Почему в данном случае сумма не равна 12?

Вот еще пару забавных примеров(с учетом вышесказанного тут все предсказуемо):
perl -e 'my $i=5; print( ${\ ("" . ++$i)} + ${\ ("" . ++$i)} )' # 13 (сохраняет вычисленный левый аргумент, как новую строку)

perl -e 'my $i=5; print( ${\ (++$i)} + ${\ ( ++$i)} )'# 14 (не сохраняет вычисленный левый аргумент)

Попробую на досуге сделать Tie-днутый скаляр и пологировать обращения.

zhdinar комментирует...

Анонимный комментирует...
>"старая" переменная увеличивается на 1, а потом
> уничтожается, т.к ...
понимаю о чем вы говорите, позвольте высказать как я все это понимаю.
приведем соответствие:
$i - ячейка памяти
5 - одно из чисел, которыми мы орудуем (сохраняем в памяти $i, либо удаляем ) исходя из этого пошагово рассмотрим действия:

1) $i = 5; - положили в ячейку памяти $i число 5
2) $i = $i++ - два арифметических действия а именно..
2.1) $i = $i; - взяли из ячейки $i цифру 5 и положили ее обратно
2.2) $i++ - взяли число 5 из ячейки, увеличили на единицу, получилось 6, положили обратно, теперь в ячейке цифра 6.

по вашей логике получается, что в пункте 2.1 мы орудовали двумя ячейками с одинаковым именем и переложили цифру 5 из одной ячейки в другую

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

koorchik комментирует...

1) $i=5;
2) $i=$i++;
2.1) вычислили правый аргумент - равен 5.
поскольку используется постфиксный инкремент - сначала возвращается значение переменной, а затем инкрементируется.
2.2) происходит инкремент переменной $i. В ней теперь 6
2.3) переменной $i присваивается ранее вычисленный правый аргумент, который равен 5.

По сути $i=$i++; можно описать так:
$right_arg = $i; $i = $i + 1; $i =$right_arg

koorchik комментирует...

В общем, ответ есть в перлдок - "никогда так не пишите" :)

Auto-increment and Auto-decrement "++" and "--" work as in C. That is, if placed before a variable, they increment or decrement the variable by one before returning the value, and if placed after, increment or decrement after returning the value.

$i = 0; $j = 0;
print $i++; # prints 0
print ++$j; # prints 1

Note that just as in C, Perl doesn't define when the variable is incremented or decremented. You just know it will be done sometime before or after the value is returned. This also means that modifying a variable twice in the same statement will lead to undefined behaviour.
Avoid statements like:

$i = $i ++;
print ++ $i + $i ++;

Perl will not guarantee what the result of the above statements is.

ЗЫ: Ну и еще может кто не знает - автоинкремент работает и на символьных строках
$i="a"; $i++; print $i # выдаст "b"

zhdinar комментирует...

>По сути $i=$i++; можно описать так:
>$right_arg = $i; $i = $i + 1; $i =$right_arg

Спасибо,пояснили все ясно и доходчиво, хотя я все-таки не согласен, в выражении $i = $i++; как ни крути cама $i должна увеличиться на 1, независимо от приоритета операции и использования временных значений

zhdinar комментирует...

только что смотрел перлдок :), истина где-то рядом

Fuksito комментирует...

Так понятное дело что нечего такое писать, перлдок как всегда прав :)

Анонимный комментирует...

Погуглите "точки следования".

koorchik комментирует...

<Погуглите "точки следования".
Спасибо за наводку.

Отправить комментарий

Не забудьте добавить себя в постоянные читатели и включить уведомления о новых комментариях, либо воспользуйтесь RSS каналом ;)