Por pura curiosidad, escribí el siguiente código:

pure struct Foo{ }
pure class Bar{ }

Esto, aparentemente, se compila tanto con DMD como con LDC. No tengo idea de lo que hace (si lo hace), ya que llamar a funciones impuras desde tales estructuras / clases está bien. Entonces, ¿qué cambia adjuntar pure a una clase o estructura?

d
3
Michail 11 nov. 2017 a las 20:21

2 respuestas

La mejor respuesta

En general, D tiende a ignorar los atributos cuando no se aplican, al menos, porque el código genérico es más fácil de escribir de esa manera (a veces, evita tener que escribir un montón de if estáticos solo para evitar aplicar atributos a código donde no tendrían ningún efecto) - un ejemplo es que puede poner static en prácticamente cualquier declaración a nivel de módulo, pero en realidad no hace nada para la mayoría de ellos, y el compilador no No te quejes de eso.

Sin embargo, por cualquier motivo, la forma en que se aplican los atributos cuando marca una estructura o clase con ellos es un poco inconsistente. Por ejemplo, si marcó una estructura o clase con @safe, entonces cada función en esa estructura o clase será @safe a menos que esté marcada con @trusted o @system. Por el contrario, si marca la clase o estructura con pure, no hace absolutamente nada, al igual que con static. Simplemente se ignora.

Mi mejor suposición de por qué se aplica algo como @safe a todas las funciones dentro de la estructura o clase, mientras que un atributo como pure o nothrow se ignora es que @safe , @trusted y @system se pueden deshacer en funciones específicas dentro de la estructura o clase utilizando un atributo diferente explícitamente en esa función, mientras que para la mayoría de los atributos, no hay forma de revertirlos.

Desafortunadamente, sin embargo, el hecho de que pueda marcar una clase o estructura con atributos cuando no se aplican o cuando se aplican solo a las declaraciones dentro de la clase o estructura y no a la clase o estructura en sí misma tiende a confundir a las personas (por ejemplo, algunos la gente piensa que immutable class C {..} significa algo especial para la clase, cuando todo lo que significa es que las declaraciones dentro de la clase son immutable; no sería diferente de hacer class C { immutable { ... } }). Entonces, en última instancia, debe estar familiarizado con lo que cada atributo hace realmente para saber cuándo se aplican realmente a la clase o estructura, cuándo realmente solo se aplican a las declaraciones dentro de la clase o estructura, y cuándo simplemente se ignoran.

Personalmente, nunca aplico atributos a una clase o estructura a menos que estén específicamente destinados a aplicarse a la estructura o clase y no a las funciones dentro de ella (por ejemplo, final en una clase significa algo diferente de ponerlo en las funciones dentro de esa clase), y la cantidad de atributos que realmente se aplican a una estructura o clase es bastante pequeña. static lo hace en algunos contextos (pero no a nivel de módulo), abstract y final lo hace para las clases, y los modificadores de acceso (public, private, etc. .) hacer. Según TDPL, synchronized también se supone que es especial para la clase, pero las clases sincronizadas nunca se han implementado realmente (solo funciones sincronizadas). Entonces, es posible que me haya perdido uno, pero en la parte superior de mi cabeza, esa es la lista completa de atributos que realmente se pueden aplicar a una estructura o clase, y todos los demás se ignoran o se aplican a las declaraciones dentro de la estructura o clase. pero no a la estructura o clase en sí.

8
Jonathan M Davis 20 nov. 2017 a las 21:45

No cambia nada. El compilador de D simplemente ignora muchas palabras clave cuando se colocan en ubicaciones que no tendrían sentido.

Una prueba rápida para probar esto:

pure struct S {
    static void bar() {}
}

pure unittest {
    static assert(!__traits(compiles, S.bar()));
}
2
BioTronic 11 nov. 2017 a las 18:15