f# - plugin - open graph facebook
Escriba las extensiones y la visibilidad de los miembros en F# (2)
¡Esta es una gran pregunta! Como señaló, la especificación dice que "los valores locales tienen un alcance léxico para el objeto que se está definiendo", pero mirando la especificación F #, en realidad no define qué significa el alcance léxico en este caso.
Como se muestra en la muestra, el comportamiento actual es que el alcance léxico de la definición del objeto es solo la definición del tipo principal (excluidas las extensiones intrínsecas). No estoy demasiado sorprendido por eso, pero veo que la otra interpretación también tendría sentido ...
Creo que una buena razón para esto es que los dos tipos de extensiones deben comportarse igual (tanto como sea posible) y usted debería ser capaz de refactorizar su código para que no use uno para usar el otro cuando lo necesite. Los dos tipos solo difieren en cómo se compilan bajo la cubierta. Esta propiedad se rompería si un tipo permitiera el acceso al alcance léxico mientras que el otro no (debido a que los miembros de la extensión, técnicamente, no pueden hacerlo).
Dicho esto, creo que esto podría (al menos) aclararse en la especificación. La mejor manera de informar esto es enviando un correo electrónico a fsbugs
en microsoft
dot com
.
F # tiene una característica llamada "Tipo de extensión" que le da a un desarrollador la capacidad de extender los tipos existentes. Hay dos tipos de extensiones: extensión intrínseca y extensión opcional . El primero es similar a los tipos parciales en C # y el segundo es algo similar a la extensión del método (pero más poderoso).
Para usar la extensión intrínseca debemos poner dos declaraciones en el mismo archivo. En este caso, el compilador fusionará dos definiciones en un tipo final (es decir, esto es dos "partes" de un tipo).
El problema es que esos dos tipos tienen reglas de acceso diferentes para diferentes miembros y valores:
// SampleType.fs
// "Main" declaration
type SampleType(a: int) =
let f1 = 42
let func() = 42
[<DefaultValue>]
val mutable f2: int
member private x.f3 = 42
static member private f4 = 42
member private this.someMethod() =
// "Main" declaration has access to all values (a, f1 and func())
// as well as to all members (f2, f3, f4)
printf "a: %d, f1: %d, f2: %d, f3: %d, f4: %d, func(): %d"
a f1 this.f2 this.f3 SampleType.f4 (func())
// "Partial" declaration
type SampleType with
member private this.anotherMethod() =
// But "partial" declaration has no access to values (a, f1 and func())
// and following two lines won''t compile
//printf "a: %d" a
//printf "f1: %d" f1
//printf "func(): %d" (func())
// But has access to private members (f2, f3 and f4)
printf "f2: %d, f3: %d, f4: %d"
this.f2 this.f3 SampleType.f4
Leí la especificación F # pero no encontré ninguna idea de por qué el compilador F # diferencia entre el valor y las declaraciones de los miembros.
En la sección 8.6.1.3 de la especificación F #, dijo que "las funciones y los valores definidos por las definiciones de instancia tienen un alcance léxico (y por lo tanto son implícitamente privados) para el objeto que se está definiendo". La declaración parcial tiene acceso a todos los miembros privados (estáticos y de instancia). Supongo que por especificación de "alcance léxico", los autores se refieren específicamente a la declaración "principal", pero este comportamiento me parece extraño.
La pregunta es: ¿este comportamiento es intencional y cuál es la razón detrás de esto?
Envié esta pregunta a fsbugs
en microsoft
dot com
y obtuve la siguiente respuesta de Don Syme:
Hola, Sergey,
Sí, el comportamiento es intencional. Cuando utiliza "let" en el ámbito de clase, el identificador tiene un alcance léxico sobre la definición de tipo. El valor ni siquiera puede colocarse en un campo; por ejemplo, si un valor no es capturado por ningún método, se convierte en local para el constructor. Este análisis se hace localmente a la clase.
Entiendo que esperas que la característica funcione como clases parciales en C #. Sin embargo, simplemente no funciona de esa manera.
Creo que el término "alcance léxico" debería definirse más claramente en la especificación, porque de lo contrario el comportamiento actual sería sorprendente para otros desarrolladores también.
¡Muchas gracias a Don por su respuesta!