openlang

pure 호스트 함수가 캐시되고, 인자에 쓴 값이 그냥 사라져요

주말 프로젝트로 D로 작성한 호스트 함수를 이름으로 등록해서 쓰는 장난감 표현식 평가기를 만들었어요. registry에 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도 괜찮고요.

시도해 본 것들: [0] 대신 new int[1]을 써 봤는데 변화 없어요. register의 delegate가 쓰기를 먹어 버리는 건가, 아니면 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[]는 mutable이라 bump는 weakly pure일 뿐이에요. 파라미터가 immutable일 때만 캐시하세요.

    영어에서 번역원문 보기
  2. 고유 링크

    제 D 레지스트리에서도 똑같은 일이 있었어요. weakly pure에 mutable 인자인데, 캐시가 쓰기를 신나게 건너뛰었죠. 저녁 한나절이 날아갔어요, 그렇죠?

    영어에서 번역원문 보기

같은 질문의 다른 갈래

  1. 같은 Int인데 타깃이 둘이면 답도 둘이에요

    같은 소스, 같은 JSON 파일인데 타깃마다 결과가 달라요. 이건 좋지 않아요. cohort_join은 우리 트래킹 시스템에서 내보낸 JSON을 읽어서 참가자를 id 기준으로 인덱싱해요. id는 타임스탬프에 카운터를 붙여서…

    답글 0최근 활동 gleam
  2. 같은 parseServices인데 잘못된 줄은 빌드할 때만 깨지나요?

    내장 테이블은 절대 안 바뀌니까 auto를 enum으로 바꿨는데, 맞죠? 이제 smtp 25(proto 없음)가 dub build를 깨뜨려요. 에러는 stderr writeln not usable at compile time…

    답글 2최근 활동 d
  3. CPS 합계가 Debug에서는 스택 오버플로를 일으키고, Release에서는 두 번째 함수만 일으켜요

    안녕하세요 여러분, 연습 삼아 continuation-passing style을 공부하고 있고, 데이터 작업용 작은 센서 도구를 쓰고 있어요. loadReadings는 리스트를 생성하고, 아직 못 만든 CSV 로더를 대신하고…

    답글 2최근 활동 fsharp