Fonctions rapides vs propriétés calculées

26

Disons que j'ai une classe Eventcomme suit:

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
    }
}

Est-il recommandé d'utiliser des fonctions ou des propriétés calculées dans les 2 cas indiqués ci-dessus?

Ashley Mills
la source
2
stackoverflow.com/questions/24035276/… ... En bref: 'Que vos fonctions soient des fonctions et vos propriétés des propriétés.'
Robert Harvey

Réponses:

14

Suivez le principe d'accès uniforme ,

Tous les services offerts par un module doivent être disponibles via une notation uniforme, qui ne trahit pas s'ils sont implémentés par le stockage ou par le calcul

Pour moi, cela signifie que je n'écris pas de fonctions qui ne prennent aucun argument et ne renvoient aucune valeur. J'utilise toujours des propriétés calculées. De cette façon, si je décide plus tard de changer la propriété calculée en une propriété stockée, je peux le faire sans avoir l'envie de supprimer les parens partout dans mon application et sans avoir une méthode "getter" distincte qui renvoie simplement la valeur d'un stocké propriété, ce qui semble IMHO assez gaspillage.

Et si je change une propriété stockée en une propriété calculée, je n'ai pas besoin d'ajouter de parens à la fin de celle-ci, et partout où elle est utilisée dans l'application.

Daniel T.
la source
À l'origine, je suis allé avec la réponse à la complexité de @ Anton, mais dans la pratique, j'ai réalisé que c'est ainsi que je le fais ... les propriétés par défaut.
Ashley Mills
17

Je dirais que cela dépend de la complexité du calcul par rapport à la fréquence d'utilisation.

  • Si c'est O(1)/ *, utilisez la propriété calculée.
  • Si c'est O(N)+/ rare-use, utilisez la fonction.
  • Si c'est O(N)+/ frequent-use, pensez si à l'avenir vous pourriez décider d'utiliser la mise en cache ou d'autres techniques "intelligentes" pour compenser la complexité, si "oui" alors utilisez la propriété, si "non-non-non, c'est juste lourd" alors utilisez la fonction .
courtoiselk
la source
2
C'est drôle comme j'ai commencé à le faire en utilisant le même raisonnement. Si vous "pouvez" lui donner l'impression d'être une propriété, même si vous devez effectuer un traitement léger, tant qu'il ne modifie pas l'objet, faites-en une propriété.
Dielson Sales
9

J'ai récemment commencé à apprendre Kotlin et ils ont une grande heuristique sur le moment d'utiliser les propriétés calculées:

Fonctions vs propriétés

Dans certains cas, les fonctions sans argument peuvent être interchangeables avec des propriétés en lecture seule. Bien que la sémantique soit similaire, il existe certaines conventions stylistiques sur le moment de préférer l'une à l'autre.

Préférez une propriété à une fonction lorsque l'algorithme sous-jacent:

  • ne jette pas
  • a une complexité O (1)
  • est bon marché à calculer (ou a été réalisé lors de la première exécution)
  • renvoie le même résultat lors des invocations

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

Daniel T.
la source
Le «ne lance pas» est également important pour Swift car les propriétés ne peuvent pas lancer (encore?)
alejandromp
"a une complexité O (1)" a été supprimé de la documentation
Mahmoud Shahoud
7

Dans Swift, les fonctions sans paramètres et propriétés calculées ont presque les mêmes capacités (il peut y avoir une différence qu'une fonction sans paramètre est également une fermeture, alors qu'une propriété calculée ne l'est pas).

La différence est sémantique. Si votre code effectue une action et retourne par exemple une description du résultat de cette action, alors j'utiliserais une fonction. Si votre code calcule une propriété mais du point de vue de l'utilisateur, cela aurait pu être une propriété stockée, ou peut-être une propriété stockée qui nécessite d'abord la mise à jour d'une valeur mise en cache, alors j'utiliserais une propriété calculée.

Une grande différence: que se passe-t-il si vous appelez deux fois la fonction ou la propriété calculée? Pour une propriété calculée, je m'attends à ce que x = propriété; la propriété y = a exactement le même comportement que la propriété x =; y = x sauf qu'il peut fonctionner un peu plus lentement. Pour les fonctions, je ne serais pas surpris si le comportement était différent.

gnasher729
la source
4

Utilisez countOfAttendeeset countOfPaidAttendees().


Une variable calculée est une variable qui renvoie une valeur calculée à chaque fois qu'elle est accédée. Autrement dit, il ne stocke pas de valeur. En interne, il est implémenté en fonction.

Quelle est la différence avec une fonction?

  • Sémantiquement, une variable est un état, une fonction est une action.
  • Une fonction régule l'accès au stockage privé. Une variable calculée peut faire de même de manière plus compacte. Exemple .
  • Une variable calculée peut être utilisée avec KVO, transmise sous la forme d'un #keypath et possède des fonctions d'observation: willSet, didSet.

Vous devez utiliser une variable lorsque

  • ça ne jette pas
  • il renvoie une propriété simple
  • il n'a pas d'effet secondaire ni de verbe dans son nom
  • c'est O (1), c'est-à-dire qu'il n'entraîne pas de coût important. Dans votre exemple, ce sera O (n).
  • c'est idempotent. Plusieurs invocations identiques renvoient la même valeur ou définissent l'objet au même état.

Raisons non pertinentes de préférer une variable à une fonction

  • Une variable calculée vous évite de taper (). Cependant, la clarté est plus importante que la brièveté, c'est donc un argument faible.
  • Une variable en lecture seule peut être remplacée en lecture / écriture. Une fonction indique qu'elle est toujours en lecture seule. Cependant, Apple utilise des propriétés pour les variables en lecture seule comme array.count. En cas de doute, recherchez la cohérence avec la plateforme.

Ressources

Extrait de  WWDC  2014-204 Quoi de neuf dans Cocoa > 24:40 Quand utiliser un @property

Utilisez la propriété pour tout ce qui concerne la valeur ou l'état d'un objet ou sa relation avec d'autres objets. Mauvais candidats:

  • Méthodes qui font les choses: charger, analyser, basculer,…. Ils ont des verbes en son nom.
  • Générateurs: init, copy, énuméré,…. Ces méthodes ne sont pas idempotentes.
  • Méthodes qui changent d'état: nextObject.

From  Swift Style by Erica Sadun  > Propriétés calculées et méthodes

Une propriété exprime la qualité inhérente d'une instance, tandis qu'une méthode effectue une action.

  • Les méthodes ont des paramètres; les propriétés ne le font pas. Préférez les méthodes pour tout appel avec effets secondaires. Si une méthode fait quelque chose (par exemple, elle charge, analyse, bascule ou imprime) ou a un nom de verbe, elle ne doit pas être une propriété.
  • Préférez les propriétés des valeurs simples que vous pouvez obtenir et / ou définir.
  • Les propriétés doivent exprimer une qualité intrinsèque sémantique d'une instance de type.
  • Les propriétés vous permettent d'ajouter des observateurs via willSet et didSet. Contrairement aux propriétés d'instance stockées, les propriétés de type stockées doivent toujours recevoir une valeur par défaut.

D'après  les conventions de codage Kotlin> fonctions vs propriétés . Voir la réponse de Daniel ci-dessus .

Autres ressources sans informations pertinentes:

Jano
la source
3

J'utiliserais un func. La programmation orientée objet fonctionne très bien sans propriétés calculées. Parce que vous récupérez une valeur qui a été calculée / filtrée, certains peuvent affirmer qu'une propriété calculée se sent bien. Mais voici ma plainte, si vous faites cela, alors la lisibilité prend un coup, car cela ressemble à une valeur.

Dans ce contexte, il ne serait pas logique d'essayer d'attribuer la valeur calculée (et heureusement, l'IDE nous aide à éviter cela), mais que se passe-t-il si j'essaie d'attribuer quelque chose qui est calculé mais qui ressemble à une valeur?

event.countOfAttendees = 0; // not possible

Lorsque vous utilisez func, l'appelant sait que vous ne traitez pas directement avec une valeur:

event.countOfAttendees()

Je pense que si c'est un objet comportemental, il devrait ressembler à un comportement plutôt qu'à une structure de données. Si votre objet est stupide et n'a aucun comportement, alors pourquoi essayer de l'encapsuler? Dans ce cas, vous pourriez tout aussi bien que les participants soient publics

morbidhawk
la source