Как эта чистая функция может изменять не приватное состояние? - PullRequest
5 голосов
/ 20 декабря 2011

TDPL, стр.167:

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

import std.stdio : writeln;

struct M{
  int[4] _data;

  pure ref int opIndex(size_t i){ return _data[i]; }
}

pure M foo(ref M m){

  m[0] = 1234;
  return m;
}

void main(){

  M m1 = M([7, 7, 7, 7]);

  writeln(m1);
  foo(m1);
  writeln(m1);
}

// output:
// M([7, 7, 7, 7])
// M([1234, 7, 7, 7])

Изменяемое состояние является временным, поскольку оно в стеке, верно?Но это не личное.Так как же foo() разрешено изменять m1?

Ответы [ 2 ]

6 голосов
/ 20 декабря 2011

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

  1. pure функции не могут получить доступ к любому модулю или статическому уровнюпеременные, которые могут быть изменены в течение программы (они должны быть const типов значений или immutable для доступа из функции pure).

  2. pureфункции не могут вызывать функции, не являющиеся pure.

  3. pure функции не могут выполнять ввод / вывод.

Вот и все.Других ограничений нет.Однако необходимы дополнительные ограничения, если функция pure будет оптимизирована таким образом, что она вызывается только один раз, даже если она используется несколько раз в выражении.А именно:

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

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

Такие pure функции иногда упоминаются как "сильно" pure, тогда как те, которые не могут быть оптимизированы, упоминаются как "слабо" pure.TDPL строго описывает функции pure.Слабые pure функции были добавлены для того, чтобы сделать pure более общедоступными.

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

Еще одна важная вещь, которая была добавлена ​​после TDPL в отношении pure, - это вывод атрибута функции.pure, nothrow и @safe выводятся для шаблонных функций (хотя не для обычных функций).Итак, если шаблонная функция может быть pure, то теперь она равна pure.Его чистота зависит от того, с чем он создан.Таким образом, становится возможным использовать pure с шаблонными функциями, тогда как раньше вы обычно не могли, потому что, если вы сделали это pure, это не сработало бы с нечистой функцией.Но если вы не не сделали его pure, то вы не могли бы использовать его с функцией pure, поэтому это было серьезной проблемой для pure.К счастью, вывод атрибутов исправляет это сейчас.Пока шаблонная функция следует приведенным выше правилам при ее создании, она считается pure.

5 голосов
/ 20 декабря 2011

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

Рассмотрим этот вполне допустимый пример, который выводит 2:

import std.stdio : writeln;

struct S
{
    int foo = 0;
    pure void set(size_t i){ foo = i; }
}


void main()
{
    S s;
    s.set(2);
    writeln(s.foo);
}

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

...