LINUX.ORG.RU

Побочные эффекты функций

 , ,


3

1

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

Но я ничего не понел.

Возьмем его же пример свободной от побочных эффектов процедуры:

procedure NegotiateSize(var res: integer);
var
  h: integer;
begin
  repeat
    write('Enter H: ');
    readln(h)
  until (h > 0) and (h mod 2 = 1);
  res := h
end;

И аналогичную функцию с побочным эффектом:

function NegotiateSize: integer;
var
  h: integer;
begin
  repeat
    write('Enter H: ');
    readln(h)
  until (h > 0) and (h mod 2 = 1);
  NegotiateSize := h
end;

Объясните мне, где тут побочный эффект?

p.s. почему подсветка кода ломается на функции?

★★★★★

Последнее исправление: Turbid (всего исправлений: 3)

Объясните мне, где тут побочный эффект?

вот же «гвозди»:

procedure NegotiateSize(var res: integer);

res := h

функция (хоть и называется она процедурой) меняет внутри себя параметр переменную res. Для внешнего уровня это совсем неочевидно и к каким последствиям это приведёт тоже.

vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 2)

вторая страница, никто не написал про хацкель.

обмельчал лор, обмельчал.

anonymous
()

Процедур без побочных эффектов быть не может. Иначе какой смысл их вызывать, они ж ничего не возвращают. Поэтому на процедуры с побочными эффектами товарищ Столяров дышит ровно. От функций ожидает чистоты и полного соответствия названию. Хотя я б не надеялся, пока компилятор не запрещает.

kabanov
()

А я вот вообще не понял, что это за процедура-функция такая. Почему она называется NegotiateSize (ОбсудитьРазмер - что за бред?)? Че за размер? Как его обсуждать? Видимо, предлагается вводить h до тех пор, пока не будет положительного четного числа. Как это связано с названием? И для чего это вообще может быть нужно? Вы там в своих универах совсем что-ли замариновались.

anonymous
()

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

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

Данунетже.

Side effect - изменение значения некоторой переменной состояния за пределами своего локального окружения, в том числе изменение изменяемого аргумента, передаваемого по ссылке.

повторный вызов одной и той же функции с одними и теми же аргументами даёт разный результат

Это одно из возможных проявлений, т.е. следствие побочного эффекта.

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

Процедур без побочных эффектов быть не может. Иначе какой смысл их вызывать, они ж ничего не возвращают

Хинт: возвращать можно не только через return

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

Хинт: возвращать можно не только через return

Ну, если по ссылке возвращать, так надо эту ссылку и передать в процедуру (что var и делает в паскале), т.е. сначала определить вне процедуры - тот же эффект.

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

Side effect - изменение значения некоторой переменной состояния за пределами своего локального окружения, в том числе изменение изменяемого аргумента, передаваемого по ссылке.

Нет такого определения сайд эффекта. То как передаются аргументы - это условность. Нет семантической разницы между return и передачей мутабельной ссылки. Более того, return имеет полное право быть реализован передачей мутабельной ссылки (и действительно так реализован в C++, где возвращаемое значение аллоцируется вызывающей стороной).

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

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

Ты понял все с точностью до наоборот.

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

Эффект процедуры в том, что она меняет то, что определено не в ней. )

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

Нет такого определения сайд эффекта.

Как так? Сайд эффект в широком смысле это изменение некоего стейта за пределами его определения.

Нет семантической разницы между return и передачей мутабельной ссылки

Как раз есть, при мутабельной ссылке нет никакой передачи и возврата, просто меняется состояние. Или что вы вложили в понятие «семантической разницы»?

vvn_black ★★★★★
()

что-то мне кажется что автор книги пытался донести обратное - передать параметр по ссылке не есть хорошо, и функция лучше. То есть side-effect как раз таки в первом случае, изменено значение чего-то внешнего.

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

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

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

fulmar_lor
()

Предположу, что это такое докапывание к словам. Типа, функции должны быть чистые, для функции это побочный эффект и плохо. А у процедуры побочного эффекта не может быть по определению, потому что для неё это эффект не побочный, а основной (иначе, зачем вообще нужны процедуры).

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

Предположу, что это такое докапывание к словам. Типа, функции должны быть чистые, для функции это побочный эффект и плохо. А у процедуры побочного эффекта не может быть по определению, потому что для неё это эффект не побочный, а основной (иначе, зачем вообще нужны процедуры).

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

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

Это всё херабора в вакууме. На деле же вот данные вот их вычисления, а вот результат. Если у тебя программа разбита на коробочки, ничего не сильно связно, код не как паутина и вот всё это. То у тебя всё норм. А если у тебя 333 функции каждая из которых меняет 333 переменные каждая из которых идёт на вход каждой из 333 функций вот тогда всё плохо ибо у тебя запутанная система где тех самых побочных эффектов попкой жуй.

+100500

По-моему, надо исходить из того в чем вообще СМЫСЛ понятия «побочный эффект»? Для программиста на практике важно знать надо ли ему учитывать, что в результате работы какого-то куска кода что-то где-то может измениться за пределами этого куска кода? Если надо - есть побочный эффект. Нет - нет его. Хотя я бы еще, с точки зрения практики, к побочным эффектам отнес и просто использование даже без модификации внешней переменной.

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

В некотором роде все без исключения обращения к внешним ресурсам (диск, периферия, сеть) - это побочный эффект.

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

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

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

для неё это эффект не побочный, а основной

Нет, у процедур в паскале основной эффект - это ничего не вернуть.

иначе, зачем вообще нужны процедуры

Ради сайд эффектов.

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

Это схоластика. И процедура и функция - это ПОДПРОГРАММЫ, которые вызывают. А как они там возвращают, если вообще возвращают, результат работы уже второстепенно и вопрос удобства. Как-то так.

praseodim ★★★★★
()
Последнее исправление: praseodim (всего исправлений: 1)

Может быть, читал бы сначала SICP какой-нибудь - не задавал бы таких вопросов.

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

Косвенно это еще влияет

Это напрямую влияет на ретроспекцию кода и на то, сколько всего надо держать в голове, чтобы понять логику кода. Чем код чище в функциональном смысле, тем по идее должно быть проще.

Отсюда и идёт популярность турбо (борланд) паскаля, наличие дебагера позволяло как угодно писать и при этом успешно дебажить.

А «чистый» можно и принтами отладить и тестами обвешать.

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

Столяров, однако, бредит. Ввод-вывод у него не побочные эффекты. Ню-ню.

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

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

Нет, @TheAnonymous правильно подметил, что раз есть side effect, то значит какой-то же должен подразумеваться и intended effect. Да, intended effect - это возвращаемое значение.

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

Да, intended effect - это возвращаемое значение.

Однако, из практических соображений какая принципиальная разница возвращается значение как результат функции или по ссылке?

С некоторых пор для чёткости в этом вопросе, в Delphi и Freepascal появился параметр out в объявлении. out - это тоже, что и var, но только для возвращения результата, то есть, переменную с out нельзя использовать, зато ей можно присваивать.

Procedure example(var a:integer; out b:integer)
begin
  a:=a+b;//Ошибка компиляции
  b:=a+10; //Так можно
  a:=a+10;// Так тоже можно.
end;
praseodim ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Если побочка функции заключается в изменении глобальной переменной которая больше НИГДЕ не используется её просто в одностороннем порядке меняют и всё.

Это уже называется говнокод. Хорошо, «рискованный стиль программирования», будем в тренде толерантности.

То технически это побочный эффект по определению, а по факту нет.

Формально.

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

Хороший эвфемизм для слова «шизоид», буду пользоваться.

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

Однако, из практических соображений какая принципиальная разница возвращается значение как результат функции или по ссылке?

В том, что второе - это сайд эффект, по определению, т.к. ты изменяешь состояние внешней переменной.

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

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

Соответственно поставим вопрос иначе, зачем вообще может быть нужно знать есть побочный эффект или нет? С твоим подходом получается формализм, который сложно представить куда приткнуть на практике.

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

Соответственно поставим вопрос иначе, зачем вообще может быть нужно знать есть побочный эффект или нет? С твоим подходом получается формализм, который сложно представить куда приткнуть на практике.

Гораздо проще исходить из того чистая ли функция или нет. Чем обсуждать побочки и пр.

anonymous
()

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

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

Если результат функции присваивается переменной, она тоже изменяется.

  1. Можно не присваивать, например, может композиция функций использоваться. 2. В нормальном языке ты объявляешь переменную и присваиешься ей значение в одном выражении (let/where expression, которые всего лишь синтаксический сахар) и это не то же самое, что изменение значения переменной.

На ассемблерном уровне, кстати, и вообще может не быть разницы в кодах.

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

Соответственно поставим вопрос иначе, зачем вообще может быть нужно знать есть побочный эффект или нет? С твоим подходом получается формализм, который сложно представить куда приткнуть на практике.

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

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

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

Объясни, какая мне, по большому счету, разница в этом смысле между двумя вариантами:


a:=func1(x); //1-й вариант
proc1(x,a); //2-й вариант

2-й вариант для одного возвращаемого значения более коряво выглядит, но если возвращается несколько значений, например, еще и статус операции:

a:=func1(x,status);
if status<>0 then begin Writeln('Shit happened'); exit;end;

то в чем проблемы? Для меня тут нет никакого side effect.

Так что получается, что в практических целях изменение переменной, передаваемой по ссылке не является side effect, по крайней мере, если оно документировано и не является неожиданным.

Вот если функция меняет что-то из глобальных переменных - это уже точно побочный эффект.

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

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

Не совсем. Напр., если отказаться от глобалок совсем. Функция которая принимает 1 и 2 и возвращает 3 по сути принимает копии 1 и 2 и возвращает свежесозданную 3.

Но если передать функции указатель на структуру. И она там что-то возвращает. И вот если она меняет эту структуру – это побочка или нет?

Потому что я ведь глобальный скоп могу вынести в структуру и пихать его в функцию. И поменяется что-то только лишь формально.

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

Но если при этом она блокирует какой-нибудь мутекс. То это уже побочка. Потому что мутекс вне функции. И возможна тупиковая ситуация (взаимная блокировка). И моск программиста должен выйти за пределы функции….

Короче с побочками – это когда моску нужно выходить за пределы функции, чтобы описать/понять её логику в целом.

Пара-па-па. Пам.

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

Объясни, какая мне, по большому счету, разница в этом смысле между двумя вариантами

Что значит какая тебе разница? Есть понятия, одни понятия строятся на других понятиях (например, одно из требований чистоты функции - это отсутствие сайд эффектов) и если ты значение одного из понятий меняешь, то значит ломаешь зависящие от него понятия. Ты тут такой приходишь и говоришь «нет, всё фигня, у меня своё понимание». Ну молодец, у тебя своё определение, оно отличается от общепринятого.

Если тебе так нужен аргумент из практики: я тебе уже говорил про композицию функций. С выходными параметрами ты ломаешь композицию.

Для меня тут нет никакого side effect.

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

Так что получается, что в практических целях изменение переменной, передаваемой по ссылке не является side effect, по крайней мере, если оно документировано и не является неожиданным.

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

fulmar_lor
()
Последнее исправление: fulmar_lor (всего исправлений: 2)

Функция без побочных эффектов - это функция результат которой зависит только от её параметров. Процедура не может быть без побочных эффектов, так как у неё нет результата, процедура вызывается ради её побочных эффектов (точнее может быть, но это пустая процедура, которая ничего не делает).

Ввод-вывод ВСЕГДА имеет побочные эффекты.

anonymous
()

Функция содержит побочные эффекты, если она изменяет среду выполнения в точке вызова.

Отсюда следует, например, что порядок вызова таких функций должен быть фиксирован и sin(x)*cos(x) уже ≠ cos(x)*sin(x), если в них есть побочные эффекты.

P.S. Так чем Столяров отличается от метапрога? Тот тоже свою терминологию придумывает. Функции чем от процедур отличаются? Да, я знаю, процедуры шершавые, а функции тугие и пахнут абстрактной сиренью.

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

sin(x)*cos(x) уже ≠ cos(x)*sin(x)

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

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

Что значит какая тебе разница? Есть понятия, одни понятия строятся на других понятиях (например, одно из требований чистоты функции - это отсутствие сайд эффектов) и если ты значение одного из понятий меняешь, то значит ломаешь зависящие от него понятия. Ты тут такой приходишь и говоришь «нет, всё фигня, у меня своё понимание». Ну молодец, у тебя своё определение, оно отличается от общепринятого.

Что не так с чистотой, если какие-то значения возвращаются по ссылке в аргументах? Тут единственное что может попортить чистоту, это если один и тот же аргумент используется и для передачи и для возврата значения. Если переменные разные (с ключевым словом out в современных паскалях или C#) - то в чем проблема с чистотой?

Если тебе так нужен аргумент из практики: я тебе уже говорил про композицию функций. С выходными параметрами ты ломаешь композицию.

Ее просто не очень красиво записывать становится.

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

Вообще, в сишечке в

sin(x)*cos(x) уже ≠ cos(x)*sin(x)

еще то западло может оказаться, если x - это макрос с таки побочными эффектами. Тогда вроде и функции без side effect, а все-равно непонятно, что происходит =)

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

P.S. Так чем Столяров отличается от метапрога? Тот тоже свою терминологию придумывает.

истинно говорю тебе: метапроги хуже мух, ибо мухи сношаются на моей голове – а метапроги ещё и в ней.

процедуры шершавые, а функции тугие и пахнут абстрактной сиренью

а разгадка одна – безблагодатность

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

Что не так с чистотой, если какие-то значения возвращаются по ссылке в аргументах?

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

Ее просто не очень красиво записывать становится.

Ты же понимаешь, что таким же «аргументом» можно и GOTO «оправдать»? Просто не очень красиво записывать становится.

fulmar_lor
()

Столяров неприятно удивил. Вроде столько книг написал, а сам путается в трёх соснах.

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

Так чем Столяров отличается от метапрога?

Кхм.

У меня есть цель софт делать, а не учиться.

Императивный, декларативный, функциональный. Lingua Latina non penis canina.

Да-да, я прекрасно программирую на Лабвью, не зная значения всех этих заумных словес. Какой стиль в Си? Императивный походу. А что такое декларативный? По функциональному мне пытались объяснять - понял, что сферический матан в вакууме для не менее чем кандидатов наук.

Если хочешь, чтоб я все это учел в Метапроге - изволь просветить доступными словами. И поменьше греческого, латыни и английского:)

Предпочитаю учиться не по книжкам. Пока получатеся.

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

прекрасно программирую на Лабвью, не зная значения всех этих заумных словес

Я как раз о весьма вольной интерпретации (или не точном понимании) значений общепринятых терминов. Метапрог «программирует на Лабвью», «не зная значения всех этих заумных словес». А Столяров, судя по данному топику, прекрасно пишет книжки с примерно тем же подходом.

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

Не говоря о том, что написанное там - бред сивой кобылы.

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

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

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