Aller au contenu


Photo

[Swift 3-4] override lazy var ?

swift lazy

  • Please log in to reply
11 réponses à ce sujet

#1 Jérémy

Jérémy

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 342 messages
  • LocationBordeaux

Posté 22 août 2017 - 08:07

Bonjour à tous !  :)

 

J'ai fait des tests hier soir sur playground et visiblement on ne peut pas surcharger une propriété lazy. Exemple :

class A {
    lazy foo: CGFloat = {
        return CGFloat(2.0)
    }()
    init(){ }
}

class B: A {
    // Ne compile pas
    override lazy foo: CGFloat = {
        return CGFloat(3.0)
    }()
    init(){ }
}

Pour contourner le problème j'ai pensé à quelque chose comme ça :

class A {
    lazy foo: CGFloat = {
        return self.getFoo()
    }()
    init(){ }
    func getFoo()-> CGFloat {
        return CGFloat(2.0)
    }
}

class B: A {
    init(){ }
    override func getFoo()-> CGFloat {
        return CGFloat(3.0)
    }
}

Mais je ne trouve pas cette solution très élégante...  -_-

 

Quelqu'un aurait il mieux à proposer ? Bien entendu le lazy n'a aucun intérêt dans le cas ci-dessus, ce qui m'intéresse c'est le principe de fonctionnement.

 

Je suis ouverte à toute proposition (décente, bien entendu).  :P


Twitter : @jrmguimberteau


#2 Joanna Carter

Joanna Carter

    Broyeur de fèves

  • Contrôleur d'arômes
  • 1 887 messages
  • LocationPlestin-les-Grèves (22)

Posté 22 août 2017 - 08:41

Ton code ne compile pas du tout. il manque le moat "var".

 

Quand même, en le corrigeant, t'as raison que l'on ne peux pas overrider les lazy vars.

 

C'est pareil avec les vars qui ne sont pas lazy mais que l'on veuille initialiser dans la déclaration :

class A
{
  var foo: CGFloat = 2.0
  
  init(){ }
}

class B: A
{
  override var foo: CGFloat = 3.0 // error : Cannot override with a stored property 'foo'
    
  override init(){ super.init() }
}

Les lazy vars ne sont que les stored vars qui sont initialisées sur le premier appel ; du coup, même principe.

 

La solution : n'utilise, ni les lazy vars, ni les vars initialisées si tu prévois les overrider.

 

Pour le comportement que tu recherches, il faut utiliser les "computed" vars :

class A
{
  var foo: CGFloat
  {
    return 2.0
  }

  init(){ }
}

class B: A
{
  override var foo: CGFloat
  {
    return 3.0
  }
  
  override init(){ super.init() }
}

Ou, si tu prévois changer la valeur après l'initialisation, tu peux faire :

class A
{
  var foo: CGFloat
  
  init(foo: CGFloat)
  {
    self.foo = foo
  }
  
  convenience init()
  {
    self.init(foo: 2.0)
  }
}

class B: A
{
  init()
  {
    super.init(foo: 3.0)
  }
}

  • colas_ aime ceci

#3 Jérémy

Jérémy

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 342 messages
  • LocationBordeaux

Posté 22 août 2017 - 09:13

Ton code ne compile pas du tout. il manque le mot "var".

 

J'ai créer ce bout de code au moment où j'ai ouvert le post. J'avais rien pour tester si ça fonctionnait.  :prie!:

 

Ouai c'est bien chiant...  ::)

 

J'avais bien pensé à ce cas là mais le souci c'est qu'à chaque appel il va recréer une instance de type CGFloat. Chaque appel de la property foo retournera un nouvel objet. J'ai juste ? Si c'est la cas ça ne me va pas...  :mellow:

 

Sinon la solution que j'ai proposée avec une surcharge de fonction, tu valides ?


Twitter : @jrmguimberteau


#4 Joanna Carter

Joanna Carter

    Broyeur de fèves

  • Contrôleur d'arômes
  • 1 887 messages
  • LocationPlestin-les-Grèves (22)

Posté 22 août 2017 - 09:23

Tu n'as pas encore dit si tu prévois changer la valeur après l'initialisation. La réponse à ta question dépend sur ce condition.

 

Dans le cas d'un CGFloat, on ne crée pas un objet ; CGFloat est un struct qui à tout modification sera copié du coup, si tu faisais :

{
  var a = A()
  
  let f = a.foo
  
  …
}

… le let f contiendra a.foo jusqu'au moment ou tu le modifie ; là il sera copié. Ça c'est la nature des structs.



#5 Jérémy

Jérémy

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 342 messages
  • LocationBordeaux

Posté 22 août 2017 - 09:37

Tu n'as pas encore dit si tu prévois changer la valeur après l'initialisation. 

 

Oui effectivement...  :P

 

En fait non, elle doit garder la valeur de la première initialisation (comme un lazy) et de mon côté ce seront des classes qui seront retournées et non des structures. ;)


Twitter : @jrmguimberteau


#6 Joanna Carter

Joanna Carter

    Broyeur de fèves

  • Contrôleur d'arômes
  • 1 887 messages
  • LocationPlestin-les-Grèves (22)

Posté 22 août 2017 - 09:49

S'il y a une possibilité que les objets dans les vars ne soit pas utilisé, tu avais raison de préférer les lazy vars.

 

Du coup, une lazy var qui appelle une méthode virtuelle sera la meilleur solution :

class BigThing
{
  let value: String
  
  init(value: String)
  {
    self.value = value
  }
}

class A
{
  func createBigThing() -> BigThing
  {
    return BigThing(value: "BigThing A")
  }
  
  lazy var foo: BigThing =
  {
    return self.createBigThing()
  }()
}

class B: A
{
  override func createBigThing() -> BigThing
  {
    return BigThing(value: "BigThing B")
  }
}

createBigThing() ne sera appeler qu'une fois, lors du premier appel au lazy var. Après ça, le lazy var gardera le même objet.



#7 Jérémy

Jérémy

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 342 messages
  • LocationBordeaux

Posté 22 août 2017 - 09:52

Ça marche ! :bravo!:  Merci beaucoup !  :)

 

Vraiment pénible qu'on ne puisse pas overrider un lazy (du moins une propriété stockée). Je vois pas trop où serait le problème...  :blink:


Twitter : @jrmguimberteau


#8 Joanna Carter

Joanna Carter

    Broyeur de fèves

  • Contrôleur d'arômes
  • 1 887 messages
  • LocationPlestin-les-Grèves (22)

Posté 22 août 2017 - 11:51

Les lazy vars sont, en substance, l'équivalent de qqch comme :

class A
{
  func createBigThing() -> BigThing
  {
    return BigThing(value: "BigThing A")
  }
  
  var foo: BigThing = createBigThing()
}

Mais, avec ça, on a l'erreur : Cannot use instance member 'createBigThing' within property initializer; property initializers run before 'self' is available

 

Du coup, c'est pour les raisons comme ça que l'on a inventé les lazy vars, qui sont, en substance, une var qui est initialisée par un closure, à la place d'une var qui ne peux pas être initialisée par une méthode.

 

En fait, on peut oublier le closure sur le lazy var en faisant :

class A
{
  func createBigThing() -> BigThing
  {
    return BigThing(value: "BigThing A")
  }
  
  lazy var foo: BigThing = self.createBigThing()
}

… parce que, en utilisant "lazy", ça dit au compilateur que la var ne puisse pas être appelé avant que "self" soit disponible.



#9 Jérémy

Jérémy

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 342 messages
  • LocationBordeaux

Posté 22 août 2017 - 16:01

… parce que, en utilisant "lazy", ça dit au compilateur que la var ne puisse pas être appelé avant que "self" soit disponible.

 

Oui c'est exactement ça. Pout être plus précis, qu'il n'est pas obligatoire que la propriété soit instanciée à l'issue de l'instanciation de la classe qui la contient. En d'autres termes, elle ne doit pas être forcément initialisé avant ou à l'issue de l'appel de la méthode init. D'où le fait (comme tu le dis) que l'on utilise généralement cette mécanique pour construire des propriétés stockées après que "self" ait été construit.

 

Je vois pas trop où serait le problème...  :blink:

 

Tu vois pas où est le problème ? Bah c'est pourtant simple. Toi tu résonnes comme si ton lazy var était une méthode. Effectivement dans le cadre d'une fonction tu peux la surcharger dans les classes filles. Alors que dans ton cas, même si tu as une closure qui te donne l'impression d'écrire une méthode, ton lazy n'est rien d'autre qu'une propriété stockée où l'instanciation de la classe qui la contient peut précéder son initialisation.  ;)

 

Ça te viendrait à l'esprit de surcharger une propriété protected ou public ( :blink:) d'une classe en Java ?  :D


Twitter : @jrmguimberteau


#10 Joanna Carter

Joanna Carter

    Broyeur de fèves

  • Contrôleur d'arômes
  • 1 887 messages
  • LocationPlestin-les-Grèves (22)

Posté 22 août 2017 - 16:32

 

Je vois pas trop où serait le problème...  :blink:

 

Tu vois pas où est le problème ?

 

Non, c'est toi qui l'a dit ; c'est toi qui a cité toi-même. Mais quand-même   ::)

 

Toi tu résonnes comme si ton lazy var était une méthode. Effectivement dans le cadre d'une fonction tu peux la surcharger dans les classes filles. Alors que dans ton cas, même si tu as une closure qui te donne l'impression d'écrire une méthode, ton lazy n'est rien d'autre qu'une propriété stockée où l'instanciation de la classe qui la contient peut précéder son initialisation.  ;)

 

Je n'ai jamais parlé d'un lazy var comme il était une méthode ; il est une propriété stockée, initialisée par une méthode (qui est une type de closure), et on peut overrider la méthode d'initialisation comme toutes autres méthodes. Mais on ne peut pas overrider le var lui-même.

 

Je ne comprends pas vraiment ce que tu veux dire. Un lazy var a été conçu exprès pour qu'il ne faille l'instancier qu'au premier appel. C'est l'équivalent de ce que l'on faisait auparavant :

class A
{
  var _foo: BigThing?
  
  var foo: BigThing
  {
    if _foo == nil
    {
      _foo = BigThing(value: "A")
    }
    
    return _foo!
  }
} 

Ça te viendrait à l'esprit de surcharger une propriété protected ou public ( :blink:) d'une classe en Java ?  :D

 

 Je ne touche jamais Java ; j'en suis allergique  :-*



#11 Draken

Draken

    Mouleur de chocolats

  • Artisan chocolatier
  • PipPipPipPipPipPipPipPip
  • 8 599 messages
  • LocationParis

Posté 22 août 2017 - 16:36

 

 Je ne touche jamais Java ; j'en suis allergique  :-*

:bravo!:


  • iLandes aime ceci

Garçon, servez-moi un Covfefe avec du lait de soja, sans OGM ..

Et faites régler la climatisation, il fait bien chaud, ici !

 

 

Éternel Novice !  :baby:

Tueur de poneys !  :(

 

Faire simple .. c'est compliqué !

Faire compliqué .. c'est simple !

 

Un MOOC (cours en ligne - dont je ne suis pas l'auteur) gratuit sur la programmation en Obj-C et en Swift 3, démarrant le 14 Mars 2017 :

https://www.edx.org/...onnex-progios1x

 

Des dizaines d'heures de tutoriels vidéo en français (je ne suis pas l'auteur) pour apprendre à développer en Obj-C et Swift : http://pagesperso-sy...don/5I452-2014/

 

 


#12 Jérémy

Jérémy

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 342 messages
  • LocationBordeaux

Posté 23 août 2017 - 13:18

Non, c'est toi qui l'a dit ; c'est toi qui a cité toi-même. Mais quand-même   ::)

 

Oui je sais, j'avais trouvé la réponse et je me répondais à moi même pour ceux qui seraient intéressés d'avoir une explication.  ;)

 

Je ne touche jamais Java ; j'en suis allergique  :-*

 

Normal, c'est super poussiéreux comme truc. Même un Dyson n'y pourra rien. Quand tu passes de Swift à Java tu as la sensation de faire un bon dans le moyen âge.  :D


Twitter : @jrmguimberteau






Also tagged with one or more of these keywords: swift, lazy

0 utilisateur(s) li(sen)t ce sujet

0 membre(s), 0 invité(s), 0 utilisateur(s) anonyme(s)