Qual é a diferença entre campos e propriedades em Julia?

23

Julia tem as funções setter setproperty!e setfield!e as funções getter getpropertye getfieldque operam em estruturas. Qual é a diferença entre propriedades e campos em Julia?

Por exemplo, o seguinte parece indicar que eles fazem a mesma coisa:

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
fonte

Respostas:

27

fieldssão simplesmente os "componentes" de uma estrutura. A estrutura

struct A
   b
   c::Int
end

tem os campos be c. Uma chamada para getfieldretorna o objeto que está vinculado ao campo:

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

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

Nas versões anteriores de Julia, a sintaxe a.bcostumava "abaixar", ou seja, ser a mesma que escrever getfield(a, :b). O que mudou agora é que a.bdiminui para getproperty(a, :b)o fallback padrão

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

Então, por padrão, nada mudou. No entanto, os autores de estruturas podem sobrecarregar getproperty(não é possível sobrecarregar getfield) para fornecer funcionalidade extra à sintaxe de pontos:

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"

Portanto, podemos adicionar funcionalidades extras à sintaxe do ponto (dinamicamente, se quisermos). Como exemplo concreto, onde isso é útil, é para o pacote PyCall.jl, onde você costumava escrever, pyobject[:field] enquanto agora é possível implementá-lo de forma que você possa escreverpyobject.field.

A diferença entre setfield! e setproperty!é análoga à diferença entre getfielde getproperty, explicada acima.

Além disso, é possível conectar-se à função Base.propertynames para fornecer a conclusão de tabulação de propriedades no REPL. Por padrão, apenas os nomes dos campos serão mostrados:

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

Mas, sobrecarregando propertynames, podemos mostrar também a propriedade extra q:

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

julia> a.<TAB><TAB>
b c q
Kristoffer Carlsson
fonte
Então você não pode sobrecarregar o getfield?
Alfaizkhan
3
Não, getfieldé uma função especial (embutida). Tentar sobrecarregar dará o erro cannot add methods to a builtin function.
Kristoffer Carlsson
Talvez adicione essa informação à resposta em algum lugar?
27413 StefanKarpinski #
2
A resposta já diz explicitamente "(não é possível sobrecarregar getfield)" e, de certa forma, ela já está lá.
Kristoffer Carlsson