Pergunta

Para aqueles que não estão familiarizados com mixins de cordas D, eles são basicamente avaliações em tempo de compilação.Você pode pegar qualquer string de tempo de compilação (seja literal ou gerada por metaprogramação de modelo ou avaliação de função de tempo de compilação) e compilá-la como código.Se você usar uma string literal simples, é basicamente copiar e colar automatizado pelo compilador.

Você consideraria um antipadrão usar mixins de strings de literais como um meio de simples reutilização de código onde outros métodos de fatoração não se encaixam?Por um lado, é basicamente copiar e colar literal automatizado pelo compilador, o que significa que, uma vez misturados, as instâncias não têm nada a ver umas com as outras.Coisas ruins acontecerão (embora em tempo de compilação, não em tempo de execução) se um símbolo no mixin de string colidir com um símbolo no escopo misto.É relativamente não estruturado, pois é possível, por exemplo, misturar uma string no meio de uma função que funcionará se e somente se as variáveis ​​no escopo forem nomeadas de acordo com uma determinada convenção.Mixins também podem declarar variáveis ​​que escopos externos podem usar como acharem adequado.

Por outro lado, como copiar e colar é automatizado pelo compilador, existe um único ponto de verdade para o código em questão no nível da fonte e se ele precisar ser modificado, ele só precisará ser modificado em um local, e tudo permanece sincronizado.Os mixins de strings também simplificam enormemente a reutilização de código que é muito difícil de fatorar de qualquer outra forma e que, de outra forma, teria uma probabilidade muito alta de ser recortado e colado manualmente.

Nenhuma solução correta

Outras dicas

Todas as críticas que você levantou são verdadeiras.

Independentemente disso, ainda é superior ao copypaste manual.

Na verdade, tenho algo semelhante em execução na minha biblioteca de ferramentas, expansão de tabela de strings.Código de exemplo, da implementação de valor dinâmico de um path tracer:

  T to(T)() {
    static if (!is(T == Scope)) {
      T value;
      if (flatType == FlatType.ScopeValue) value = sr.value().to!(T);
    }
    const string Table = `
                 | bool          | int         | string               | float   | Scope
      -----------+---------------+-------------+----------------------+---------+----------
      Boolean    | b             | b           | b?q{true}p:q{false}p | ø       | ø
      Integer    | i != 0        | i           | Format(i)            | i       | ø
      String     | s == q{true}p | atoi(s)     | s                    | atof(s) | ø
      Float      | ø             | cast(int) f | Format(f)            | f       | ø
      ScopeRef   | !!sr          | ø           | (sr?sr.fqn:q{(null:r)}p) | ø   | sr
      ScopeValue | value         | value       | value                | value   | sr`;
    mixin(ctTableUnrollColMajor(Table,
      `static if (is(T == $COL))
        switch (flatType) {
          $BODY
          default: throw new Exception(Format("Invalid type: ", flatType));
        }
      else `,
      `case FlatType.$ROW:
        static if (q{$CELL}p == "ø")
          throw new Exception(q{Cannot convert $ROW to $COL: }p~to!(string)~q{! }p);
        else return $CELL;
      `
    ).litstring_expand() ~ `static assert(false, "Unsupported type: "~T.stringof); `);
  }

Tenho certeza de que é fácil ver que confusão horrível e redundante de instruções ifs e case aninhadas que existiriam sem mixins de strings - dessa forma, toda a feiúra está concentrada na parte inferior, e o real comportamento da função é fácil de ler rapidamente.

Embora outras soluções mais elegantes possam ser melhores para usar, se possível, os mixins de strings podem ser extremamente úteis.Eles permitem a reutilização e a geração de código.Eles são verificados em tempo de compilação.O código resultante é exatamente o mesmo que se você o tivesse escrito à mão, portanto não é menos seguro do que se você o tivesse escrito à mão.

O problema com mixins de strings é que eles são mais difíceis de controlar do que códigos escritos à mão, no sentido de que não estão fisicamente dispostos em sua fonte da mesma maneira, com números de linha claramente rastreáveis ​​a erros, e podem ser mais difíceis de depurar.Por exemplo, veja olá mundo com um mixin de strings:

import std.stdio;

void main()
{
    mixin(hello());
}

string hello()
{
    return "
    writeln(\"hello world\");
";
}

Se retirássemos o ponto e vírgula depois writeln(), então o erro que obtivemos seria

d.d(7): found 'EOF' when expecting ';' following statement

O mixin é feito na linha 5.A linha 7 é uma linha em branco.Portanto, o número da linha tem utilidade limitada aqui.Agora, esse mixin é curto o suficiente para que pudéssemos colocá-lo em uma única linha e dizer que o erro estava na mesma linha do mixin, mas com mixins mais complicados, isso obviamente não funcionará.Portanto, ao usar um mixin de strings, sua capacidade de descobrir onde está um erro é prejudicada.Se o código for gerado usando CTFE, seria muito mais difícil descobrir exatamente como o código se parece para descobrir o que há de errado com ele.É como descobrir em que código uma macro estilo C se transforma, exceto que poderia ser pior porque eles poderiam ser gerados em vez de uma substituição direta.No entanto, eles não substituem, exceto onde você explicitamente os instrui, portanto, são muito mais seguros que as macros estilo C.

Os mixins de cordas são totalmente seguros e não há nada de particularmente errado com eles, mas dificultam a manutenção em alguns aspectos.O código escrito à mão correspondente seria mais fácil de depurar.No entanto, os mixins de string são poderosos o suficiente para gerar muita geração de código para você e economizar muitos custos de manutenção nesse sentido, além de permitirem a reutilização do código, o que também pode ser um grande ganho de manutenção.

Portanto, se usar um mixin de strings é uma boa ideia em uma situação específica depende dessa situação.Não vejo nada de particularmente errado com eles e certamente não os chamaria de antipadrão, mas há prós e contras em usá-los, de modo que se são uma boa ideia depende do que você está fazendo .Em muitos casos, existem soluções mais elegantes e limpas que seriam melhores.Em outros, são exatamente o que o médico receitou.

Pessoalmente, acho que eles são fantásticos se você deseja gerar código, evitando o esforço de ter que escrever esse código manualmente e possivelmente facilitando a geração do código correto para uma variedade de situações e evitando o risco de criar novos bugs como você pode ter escrito você mesmo em cada um dos lugares onde usou o mixin.Também é uma das maneiras de reutilizar código completamente sem ter que se preocupar com o custo de uma chamada de função ou problemas com os limites da herança única ou qualquer outra coisa que torne a reutilização de código chamando funções ou herança mais difícil.Você está simplesmente copiando e colando o código em cada lugar de uma maneira que faz com que, se você alterar o código, as alterações sejam coladas corretamente em todos os lugares, sem que você precise se preocupar em rastreá-las, como se você tivesse copiado manualmente e colado.

Portanto, use mixins de strings quando apropriado e provavelmente é melhor não usá-los se não forem necessários, mas não há nada realmente errado em usá-los.

O mixin de strings é como goto:deve ser evitado sempre que possível e usado sempre que necessário.

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