Funções Swift vs propriedades calculadas

26

Digamos que eu tenha uma aula da Eventseguinte maneira:

class Event {
    private var attendees: [Person] = []

    // Case 1
    //*******
    // Should I use a func…
    func countOfAttendees() -> Int {
        return attendees.count
    }

    // …or a var
    var countOfAttendees: Int {
        return attendees.count
    }

    // Case 2
    //*******
    // Should I use a func…
    func countOfPaidAttendees() -> Int {
        return attendees.filter({$0.hasPaid}).count
    }

    // …or a var
    var countOfPaidAttendees: Int {
        return attendees.filter({$0.hasPaid}).count
    }
}

É uma prática recomendada usar funções ou propriedades calculadas nos 2 casos indicados acima?

Ashley Mills
fonte
2
stackoverflow.com/questions/24035276/… ... Em resumo: 'Deixe suas funções serem funções e suas propriedades sejam propriedades.'
Robert Harvey

Respostas:

14

Siga o Princípio de acesso uniforme ,

Todos os serviços oferecidos por um módulo devem estar disponíveis por meio de uma notação uniforme, que não trai se eles são implementados por armazenamento ou por computação

Para mim, isso significa que não escrevo funcs que não recebem argumentos e retornam um valor. Eu sempre uso propriedades computadas. Dessa forma, se eu decidir posteriormente alterar a propriedade computada para uma propriedade armazenada, posso fazê-lo sem ter o desejo de remover as parênteses em todos os lugares no meu aplicativo e sem ter um método "getter" separado que apenas retorne o valor de uma propriedade armazenada. propriedade, o que parece bastante desperdício IMHO.

E se eu alterar uma propriedade armazenada em uma computada, não preciso adicionar parênteses ao final e a qualquer lugar em que ela for usada no aplicativo.

Daniel T.
fonte
Originalmente, fui com a resposta de complexidade do @ Anton, mas, na prática, percebi que é assim que faço ... propriedades por padrão.
Ashley Mills
17

Eu diria que depende da complexidade do cálculo versus da frequência de uso.

  • Se for O(1)/ *, use a propriedade computada.
  • Se for O(N)+/ rare-use, use a função
  • Se for O(N)+/ frequent-use, pense se, no futuro, você pode optar por usar o cache ou outras técnicas "inteligentes" para compensar a complexidade; se "sim", use a propriedade; se "não-não-não, é apenas pesado", use a função .
cortês
fonte
2
Engraçado como comecei a fazê-lo usando o mesmo raciocínio. Se você "puder" dar a impressão de ser uma propriedade, mesmo que precise fazer um processamento leve, desde que ele não mude o objeto, torne-o uma propriedade.
precisa
9

Recentemente, comecei a aprender Kotlin e eles têm uma ótima heurística sobre quando usar propriedades computadas:

Funções vs Propriedades

Em alguns casos, funções sem argumentos podem ser intercambiáveis ​​com propriedades somente leitura. Embora a semântica seja semelhante, existem algumas convenções estilísticas sobre quando preferir uma à outra.

Prefira uma propriedade a uma função quando o algoritmo subjacente:

  • não joga
  • tem uma complexidade O (1)
  • é barato de calcular (ou capturado na primeira execução)
  • retorna o mesmo resultado sobre invocações

- https://kotlinlang.org/docs/reference/coding-conventions.html

Daniel T.
fonte
O 'não joga' também é importante para o Swift porque as propriedades ainda não podem ser lançadas ()?
alejandromp
"tem uma complexidade O (1)" foi removido da documentação
Mahmoud Shahoud
7

No Swift, funções sem parâmetros e propriedades calculadas têm quase os mesmos recursos (pode haver uma diferença de que uma função sem parâmetro também seja um fechamento, enquanto uma propriedade calculada não).

A diferença é semanticamente. Se o seu código executar uma ação e retornar, por exemplo, uma descrição do resultado dessa ação, eu usaria uma função. Se o seu código calcula uma propriedade, mas do ponto de vista do usuário, isso poderia ter sido uma propriedade armazenada ou talvez uma propriedade armazenada que exija a atualização de algum valor em cache primeiro, então eu usaria uma propriedade calculada.

Uma grande diferença: o que acontece se você chamar a função ou a propriedade calculada duas vezes? Para uma propriedade calculada, espero que x = propriedade; y = propriedade tem exatamente o mesmo comportamento que x = propriedade; y = x, exceto que pode ser um pouco mais lento. Para funções, eu não ficaria surpreso se o comportamento fosse diferente.

gnasher729
fonte
4

Use countOfAttendeese countOfPaidAttendees().


Uma variável calculada é aquela que retorna um valor calculado cada vez que é acessado. Ou seja, ele não armazena um valor. Internamente, é implementado como uma função.

Qual é a diferença com uma função?

  • Semanticamente, uma variável é estado, uma função é uma ação.
  • Uma função regula o acesso ao armazenamento privado. Uma variável calculada pode fazer o mesmo de uma maneira mais compacta. Exemplo .
  • Uma variável computada pode ser usada com o KVO, transmitida como um #keypath, e possui recursos para observar: willSet, didSet.

Você deve usar uma variável quando

  • não joga
  • retorna uma propriedade simples
  • não tem um efeito colateral ou um verbo em seu nome
  • é O (1), ou seja, não incorre em um custo significativo. No seu exemplo, será O (n).
  • é idempotente. Várias invocações idênticas retornam o mesmo valor ou configuram o objeto para o mesmo estado.

Razões irrelevantes para preferir uma variável a uma função

  • Uma variável computada evita que você digite (). No entanto, a clareza é mais importante que a brevidade, portanto esse é um argumento fraco.
  • Uma variável somente leitura pode ser substituída como leitura / gravação. Uma função indica que é sempre somente leitura. No entanto, a Apple usa propriedades para variáveis ​​somente leitura, como array.count. Em caso de dúvida, procure consistência com a plataforma.

Recursos

Da  WWDC 2014 - 204 O que há de novo no cacau  > 24:40 Quando usar uma @property

Use propriedade para qualquer coisa que seja sobre o valor ou estado de um objeto ou seu relacionamento com outros objetos. Candidatos ruins:

  • Métodos que fazem coisas: carregar, analisar, alternar,…. Eles têm verbos no nome.
  • Geradores: init, cópia, enumerado,…. Esses métodos não são idempotentes.
  • Métodos que mudam de estado: nextObject.

From  Swift Style por Erica Sadun  > Propriedades computadas vs. Métodos

Uma propriedade expressa uma qualidade inerente de uma instância, enquanto um método executa uma ação.

  • Métodos têm parâmetros; propriedades não. Prefira métodos para qualquer chamada com efeitos colaterais. Se um método faz alguma coisa (por exemplo, carrega, analisa, alterna ou imprime) ou tem um nome de verbo, não deve ser uma propriedade.
  • Prefira propriedades para valores simples que você pode obter e / ou definir.
  • As propriedades devem expressar uma qualidade intrínseca semântica de uma instância de tipo.
  • As propriedades permitem adicionar observadores via willSet e didSet. Diferentemente das propriedades da instância armazenada, as propriedades do tipo armazenado sempre devem receber um valor padrão.

Nas  convenções de codificação Kotlin> funções x propriedades . Veja a resposta de Daniel acima .

Outros recursos sem informações relevantes:

Jano
fonte
3

Eu usaria um func. A programação orientada a objetos funciona bem sem propriedades calculadas. Como você está recuperando um valor calculado / filtrado, alguns podem argumentar que uma propriedade calculada parece correta. Mas aqui está a minha reclamação: se você fizer isso, a legibilidade será afetada, porque parece um valor.

Nesse contexto, não faria sentido tentar atribuir o valor calculado (e, felizmente, o IDE nos ajuda a evitar isso), mas e se eu tentar atribuir algo que seja calculado, mas pareça um valor?

event.countOfAttendees = 0; // not possible

Ao usar o func, o responsável pela chamada sabe que você não está lidando com um valor diretamente:

event.countOfAttendees()

Eu acho que se é um objeto comportamental, deve parecer que se comporta em vez de parecer uma estrutura de dados. Se seu objeto é burro e não tem nenhum comportamento, por que tentar encapsulá-lo? Nesse caso, é possível que apenas os participantes sejam públicos

morbidhawk
fonte