openlang

pure host-функцию кэшируют, и запись в её аргумент просто пропадает

Проект на выходные: игрушечный вычислитель выражений с host-функциями на D, регистрируются по имени. Добавил в реестр memo-кэш (очень горжусь им, всю неделю хвастаюсь). Правило такое: если функция pure, у неё не может быть побочных эффектов, значит кэшируем результат по ключу из имени и напечатанных аргументов.

Потом написал bump, которая увеличивает на единицу первый элемент полученного массива. На каждом шаге цикла создаётся новый counter = [0], вызывается bump, потом печать. Я ожидал каждый раз [1]. Получаю step 0: counter=[1], затем step 1: counter=[0] и step 2: counter=[0]. С --verbose на шагах 1 и 2 видно попадание в кэш.

tick (не pure, увеличивает глобальную переменную) работает нормально. twice тоже.

Что пробовал: new int[1] вместо [0], без изменений. Думал, что delegate в register съедает запись, или что functionAttributes врёт, но печать флага показывает, что bump действительно pure. Компилятор принял её без единого писка. (argparse есть в Phobos, так что дело не в нём.)

Разве pure не должен быть маркером того, что кэшировать безопасно? Почему запись просто пропускается?

// host.d
pure void bump(int[] a)
{
    a[0]++;
}
// cache.d
enum attrs = functionAttributes!fn;
r.cacheable[name] = (attrs & FunctionAttribute.pure_) != 0;

int[] call(ref Registry r, string name, int[] args)
{
    if (r.cacheable[name])
    {
        auto key = name ~ args.to!string;
        if (auto p = key in r.memo)
        {
            r.hits++;
            return *p;
        }
        r.misses++;
        auto res = r.fns[name](args);
        r.memo[key] = res;
        return res;
    }
    return r.fns[name](args);
}
// app.d
foreach (i; 0 .. opts.steps)
{
    auto counter = [0];
    reg.call("bump", counter);
    writeln("step ", i, ": counter=", counter);
}
Переведено с английскогоПоказать оригинал

Разговор продолжается 2

Следуя доводам
  1. Ссылка на ответ

    если функция pure, у неё не может быть побочных эффектов

    в D может, если она трогает только свои аргументы. int[] изменяемый, так что bump только weakly pure. кэшируйте только когда параметры immutable.

    Переведено с английскогоПоказать оригинал

Другие стороны того же вопроса

  1. Один и тот же Int, два таргета, два разных результата

    Один и тот же исходник, один и тот же JSON-файл, а результат зависит от таргета. Это плохо. cohort_join читает JSON-экспорт и…

    Ответы 0Последняя активность gleam
  2. тот же parseServices, а плохая строка ломает только на этапе сборки?

    Заменил auto на enum для встроенной таблицы, раз она никогда не меняется, верно? Теперь smtp 25 (без proto) ломает dub build,…

    Ответы 2Последняя активность d
  3. CPS-сумма переполняет стек в Debug, а в Release — только вторая функция

    Всем привет, Разбираюсь с continuation-passing style в качестве упражнения, на небольшой утилите для сенсоров, которую исполь…

    Ответы 2Последняя активность fsharp