¿Cuál es la diferencia entre campos y propiedades en Julia?

23

Julia tiene las funciones setter setproperty!y setfield!y getter getpropertyy getfieldque funcionan en estructuras. ¿Cuál es la diferencia entre propiedades y campos en Julia?

Por ejemplo, lo siguiente parece indicar que hacen lo mismo:

julia> mutable struct S
           a
       end

julia> s = S(2)
S(2)

julia> getfield(s, :a)
2

julia> getproperty(s, :a)
2

julia> setfield!(s, :a, 3)
3

julia> s
S(3)

julia> setproperty!(s, :a, 4)
4

julia> s
S(4)
Kristoffer Carlsson
fuente

Respuestas:

27

fieldsson simplemente los "componentes" de una estructura. La estructura

struct A
   b
   c::Int
end

tiene los campos by c. Una llamada a getfielddevuelve el objeto que está vinculado al campo:

julia> a = A("foo", 3)
A("foo", 3)

julia> getfield(a, :b)
"foo"

En las primeras versiones de Julia, la sintaxis a.bsolía "bajar", es decir, ser lo mismo que escribir getfield(a, :b). Lo que ha cambiado ahora es que se a.breduce a getproperty(a, :b)la reserva predeterminada

getproperty(a::Type, v::Symbol) = getfield(a, v)

Entonces, por defecto, nada ha cambiado. Sin embargo, los autores de estructuras pueden sobrecargar getproperty(no es posible sobrecargar getfield) para proporcionar funcionalidad adicional a la sintaxis de puntos:

julia> function Base.getproperty(a::A, v::Symbol)
           if v == :c
               return getfield(a, :c) * 2
           elseif v == :q
               return "q"
           else
               return getfield(a, v)
           end
       end

julia> a.q
"q"

julia> getfield(a, :q)
ERROR: type A has no field q

julia> a.c
6

julia> getfield(a, :c)
3

julia> a.b
"foo"

Entonces podemos agregar funcionalidad adicional a la sintaxis de puntos (dinámicamente si lo deseamos). Como un ejemplo concreto donde esto es útil es para el paquete PyCall.jl donde solía tener que escribir, pyobject[:field] mientras que ahora es posible implementarlo de manera que pueda escribirpyobject.field.

La diferencia entre setfield!y setproperty!es análoga a la diferencia entre getfieldy getproperty, explicada anteriormente.

Además, es posible conectarse a la función Base.propertynamespara proporcionar la finalización de tabulación de propiedades en REPL. Por defecto, solo se mostrarán los nombres de los campos:

julia> a.<TAB><TAB>
b c

Pero al sobrecargar propertynamespodemos hacer que también muestre la propiedad adicional q:

julia> Base.propertynames(::A) = (:b, :c, :q)

julia> a.<TAB><TAB>
b c q
Kristoffer Carlsson
fuente
¿Entonces no puedes sobrecargar getfield?
Alfaizkhan
3
No, getfieldes una función especial (incorporada). Intentar sobrecargarlo dará el error cannot add methods to a builtin function.
Kristoffer Carlsson
¿Quizás agregar esa información a la respuesta en alguna parte?
StefanKarpinski
2
La respuesta ya dice explícitamente "(no es posible sobrecargar getfield)", por lo que, en cierto sentido, ya está allí.
Kristoffer Carlsson