Pergunta

Enquanto a brincar com D 2.0 Eu encontrei o seguinte problema:

Exemplo 1:

pure string[] run1()
{
   string[] msg;
   msg ~= "Test";
   msg ~= "this.";
   return msg;
}

Isso compila e funciona como esperado.

Quando tento enrole a matriz de cadeia em uma classe eu acho que eu não posso chegar a este trabalho:

class TestPure
{
    string[] msg;
    void addMsg( string s )
    {
       msg ~= s;
    }
};

pure TestPure run2()
{
   TestPure t = new TestPure();
   t.addMsg("Test");
   t.addMsg("this.");
   return t;
}

Este código não irá compilar porque a função addMsg é impuro. Eu não posso fazer essa função pura, uma vez que altera o objeto TestPure. Estou esquecendo de algo? Ou esta é uma limitação?

A seguir faz compilação:

pure TestPure run3()
{
    TestPure t = new TestPure();
    t.msg ~= "Test";
    t.msg ~= "this.";
    return t;
}

O relator ~ = operador não foi implementado como uma função impuro da matriz msg? Como é que o compilador não reclamar sobre isso na função RUN1?

Foi útil?

Solução

Desde v2.050, D relaxou a definição de pure para aceitar as chamadas funções "fracamente puros" também. Isto refere-se às funções que " não ler ou escrever qualquer mutável mundial estado ". Fracamente funções puras são não as mesmas funciona como puros no sentido linguagem funcional. A única relação é que torna as funções reais puros, também chamadas funções "fortemente puros" chamada capazes os fracos, como o exemplo do OP.

Com isso, addMsg pode ser marcado como (fracamente) pure, uma vez que apenas o this.msg variável local é alterado:

class TestPure
{
    string[] msg;
    pure void addMsg( string s )
    {
       msg ~= s;
    }
};

e, claro, agora você pode usar o (fortemente) pure função run2 sem modificação.

pure TestPure run2()
{
   TestPure t = new TestPure();
   t.addMsg("Test");
   t.addMsg("this.");
   return t;
}

Outras dicas

Outros já têm apontado que addMsg não é puro e não pode ser puro, pois transforma o estado do objeto.

A única maneira de torná-lo puro é encapsular o que você está fazendo mudanças. A maneira mais fácil de fazer isso é através de mutação retorno, e há duas maneiras de implementar isso.

Em primeiro lugar, você poderia fazê-lo como este:

class TestPure
{
    string[] msg;
    pure TestPure addMsg(string s)
    {
        auto r = new TestPure;
        r.msg = this.msg.dup;
        r.msg ~= s;
        return r;
    }
}

Você precisa copiar a matriz anterior, porque dentro de uma função pura, a esta referência é realmente const. Note que você poderia fazer a cópia melhor através da atribuição de uma nova matriz do tamanho final e, em seguida, copiar os elementos em si mesmo. Você usaria essa função assim:

pure TestPure run3()
{
    auto t = new TestPure;
    t = t.addMsg("Test");
    t = t.addMsg("this.");
    return t;
}

Desta forma, a mutação está confinado a cada função pura com as mudanças aprovadas para fora através de valores de retorno.

Uma forma alternativa de escrever TestPure seria fazer os membros const e fazer tudo a mutação antes de passá-lo para o construtor:

class TestPure
{
    const(string[]) msg;
    this()
    {
        msg = null;
    }
    this(const(string[]) msg)
    {
        this.msg = msg;
    }
    pure TestPure addMsg(string s)
    {
        return new TestPure(this.msg ~ s);
    }
}

Espero que ajude.

Por favor, reveja a definição de funções puras:

funções puras são funções que produzem o mesmo resultado para os mesmos argumentos. Para o efeito, a função pura:

  • tem parâmetros que são todos invariante ou são implicitamente conversível para invariante
  • não ler ou escrever qualquer estado mutável mundial

Um dos efeitos do uso de funções puras é que eles podem ser paralelizado com segurança. No entanto, não é seguro para executar várias instâncias de sua função em paralelo, porque eles poderiam tanto modificar a instância da classe simultaneamente, causando um problema de sincronização.

I pensar que o seu código é conceitualmente correto. No entanto, você pode ter encontrado caso em análise semântica do compilador não é tão bom quanto o seu cérebro de.

Considere o caso em que fonte da classe não está disponível. Em que casos o compilador teria nenhuma maneira de dizer que a variável addMsg apenas modifica membro para que ele não pode permitir que você chamá-lo de uma função pura.

Para permitir que no seu caso, ele teria que ter tratamento especial caso para este tipo de uso. Toda regra caso especial adicionado torna a linguagem mais complicado (ou, se deixados em situação irregular, torna menos portátil)

Apenas um palpite, mas esta função não retornar sempre o mesmo resultado.

Veja, ele retorna uma referência a algum objeto, e enquanto o objeto sempre conterá os mesmos dados, os objetos retornados por várias chamadas para as mesmas funções não são idênticas; isto é, eles não têm o mesmo endereço de memória.

Quando você retornar uma referência para o objeto, você está retornando essencialmente um endereço de memória, que vai ser diferente em várias chamadas.

Outra maneira de pensar sobre isso, parte do valor de retorno é o endereço de memória de um objeto, que é dependente de algum estado global (s), e se a saída de uma função depende do estado global, então não é puro . Inferno, ele mesmo não tem que depender dela; enquanto uma função lê um estado global, então não é puro. Ao chamar "novo", você está lendo estado global.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top