Aller au contenu


Photo

Accès aux membres d'une struct par nom et par indice

Swift struct propriétés

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

#21 Draken

Draken

    Mouleur de chocolats

  • Artisan chocolatier
  • PipPipPipPipPipPipPipPip
  • 8 585 messages
  • LocationParis

Posté 02 février 2017 - 18:27

Ou, pour jouer plus avec le vecteur de Céroce :

 

Oui, mais tu retournes des Float?. Il n'y a pas de perte de performance par rapport à des Float classique, même minime ? L'utilisation de Céroce est assez .. intense, vu qu'il s'agit d'un immense flux de données graphiques.


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/

 

 


#22 Joanna Carter

Joanna Carter

    Broyeur de fèves

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

Posté 02 février 2017 - 18:58

Oui, mais tu retournes des Float?. Il n'y a pas de perte de performance par rapport à des Float classique, même minime ? L'utilisation de Céroce est assez .. intense, vu qu'il s'agit d'un immense flux de données graphiques.


C'est comme beaucoup de subscripts qui renvoie les optionals en cas d'échec comme index hors limites, à la place de throw

#23 Pyroh

Pyroh

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 473 messages

Posté 03 février 2017 - 07:58



C'est comme beaucoup de subscripts qui renvoie les optionals en cas d'échec comme index hors limites, à la place de throw

Oui mais là non...

 

Si on prend ce cas précis on est assuré qu'à chaque fois qu'on va utiliser une instance de Vector on aura les composantes x, y, z. C'est comme ça c'est un vecteur 3D.

 

Si on ajoute des subscript on sera également assurés que les indices 0, 1, 2 correspondrons respectivement au trois composantes sus-nommées. Pareil pour les clés "x", "y", "z". En dehors de ces indices et clés il n'y a aucune chance qu'aucun autre ne soit valide.

Dans ce cas là c'est fatalError sans se poser de question, pareil que pour un index out of bounds sur un Array. Si le codeur essaie de récupérer une quatrième composante c'est qu'il n'a pas compris un truc. 

 

Faire retourner un Float? dans ce cas reviendrai à dire : "Je sais pas, essaie, on verra bien ce qu'on a !" alors que pas du tout ! Il n'y a aucune ambiguïté à aucun moment.

Les optionals sont là pour assainir le concept de nullité dans les cas qu'on ne peut pas prévoir avant qu'ils ne surviennent. Ici on peut tout prévoir, la clé "w" ne renverra jamais rien, ni au moment de l'écriture du code, ni lors du runtime, jamais. Pareil pour l'indice 6. Alors pas de throw, pas d'optional.

 

En plus ça va plomber les performances sans raison valable. L'optional binding c'est pas gratos non plus, ça peut être négligeable sur une dizaine de vecteurs mais au delà on fait clairement de la contre-optimisation et ça craint.

 

Après il y a le cas Array vs Dictionary. Array[i] renvoie un objet de type Element tandis que Dictionary[key] renvoie un Element?. La raison est simple on peut vérifier le nombre d'éléments contenus dans un Array avec count. On est alors assuré que les indices 0..<count sont valides et reverrons quelque choses parce qu'on sait que l'indice de début est toujours 0 par convention. 

Dans le cadre du Dictionary on peut aussi savoir combien il y a d'éléments dans la collection mais cette information n'est pas déterminante. Comme les clés ne sont pas comprise dans un range il n'y a aucun moyen de les déduire sans les connaitre. De plus l'intérêt du Dictionary est de pouvoir avoir une collection dynamique dans laquelle l'absence d'un élément est une information en soit. Ici les optionals font alors sens.

 

Les optionals sont une très bonne chose et sont très pratiques (je vous renvoie au blog d'Ali pour ça) mais il faut vraiment savoir pourquoi et quand les utiliser sinon ça devient vite contre-intuitif.


Modifié par Pyroh, 03 février 2017 - 09:41 .


#24 Céroce

Céroce

    Mouleur de chocolats

  • Contrôleur d'arômes
  • 5 206 messages
  • LocationSaint-Leu-d'Esserent / France

Posté 03 février 2017 - 09:17

En plus ça va plomber les performances sans raison valable. L'optional binding c'est pas gratos non plus, ça peut être négligeable sur une dizaine de vecteurs mais au delà on fait clairement de la contre-optimisation et ça craint.

Sans compter la lisibilité, à chaque fois il faudrait une construction if let component = vec[2].

Je suis d'accord que les optionals ne sont pas appropriés ici. Dans le principe on pourrait lever une exception, mais là encore, ça obligerait à utiliser des blocs de try {}. Utiliser une assertion me parait le plus adéquat, d'autant plus que les assertions sont désactivées en Release.
RenaudPradenc.com Je suis développeur iOS & Mac indépendant.

#25 Draken

Draken

    Mouleur de chocolats

  • Artisan chocolatier
  • PipPipPipPipPipPipPipPip
  • 8 585 messages
  • LocationParis

Posté 03 février 2017 - 10:36

Sans compter la lisibilité, à chaque fois il faudrait une construction if let component = vec[2].
 

 

f

Bah non, si tu es certain de l'existence de la donnée, tu peux forcer sa conversion.

r

let x = vec[2]!


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/

 

 


#26 Céroce

Céroce

    Mouleur de chocolats

  • Contrôleur d'arômes
  • 5 206 messages
  • LocationSaint-Leu-d'Esserent / France

Posté 03 février 2017 - 10:46

Si systématiquement, je force l'unwrapping, à quoi peut bien servir un optional ?!
RenaudPradenc.com Je suis développeur iOS & Mac indépendant.

#27 Draken

Draken

    Mouleur de chocolats

  • Artisan chocolatier
  • PipPipPipPipPipPipPipPip
  • 8 585 messages
  • LocationParis

Posté 03 février 2017 - 10:57

A rien dans ce cas précis. C'est inutile et contre-productif d'utiliser des optionals sur des données dont l'existence est certaine.

Je pense que Joanna a utilisé un Float? pour simplifier l'écriture du code et éviter le gag du "return Float()" de Pyroh, qui ne sert qu'à éviter un hurlement de rage d'Xcode.


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/

 

 


#28 Joanna Carter

Joanna Carter

    Broyeur de fèves

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

Posté 03 février 2017 - 11:45

Si, comme Draken on ne veut pas tuer les poneys, on peut toujours utiliser un enum pour l'index :

struct Vector
{
  enum Index : Int
  {
    case x = 0
    case y
    case z
  }
  
  var x: Float
  
  var y: Float
  
  var z: Float
  
  subscript(index: Index) -> Float?
  {
    get
    {
      switch index
      {
        case .x : return self.x
        
        case .y : return self.y
        
        case .z : return self.z
      }
    }
  }
}

Donc, on est garanti de ne pas excéder les limites.



#29 Jérémy

Jérémy

    Ecabosseur en fèves

  • Membre
  • PipPipPipPip
  • 342 messages
  • LocationBordeaux

Posté 03 février 2017 - 11:50

Je vois pas trop l'intérêt de faire ça :

vector[x]

si on peut faire ça :

vector.x

Twitter : @jrmguimberteau


#30 Joanna Carter

Joanna Carter

    Broyeur de fèves

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

Posté 03 février 2017 - 11:58

Car à la place des Ints pour les indexes, on aurait un type intégral qui garanti de ne pas dépasser les limites



#31 Céroce

Céroce

    Mouleur de chocolats

  • Contrôleur d'arômes
  • 5 206 messages
  • LocationSaint-Leu-d'Esserent / France

Posté 03 février 2017 - 12:06

Je vois pas trop l'intérêt de faire ça :

vector[x]
si on peut faire ça :
vector.x


Extrait de mon code:

struct BoundingBox {
    let minPoint: Vec3
    let maxPoint: Vec3

    func isHitBy(ray: Ray, distMin: Float, distMax: Float) -> Bool {
        var tmin = distMin
        var tmax = distMax
        
        for component in 0..<3 {
            let invD = Float(1.0) / ray.direction[component]
            let t0 = (minPoint[component] - ray.origin[component]) * invD
            let t1 = (maxPoint[component] - ray.origin[component]) * invD
            tmin = max(tmin, min(t0, t1))
            tmax = min(tmax, max(t0, t1))
    
            if tmax <= tmin {
                return false
            }
        }
        
        return true
    }
}
Sans l'accès aux composantes par indice, on doit répéter 3 fois le même code.
RenaudPradenc.com Je suis développeur iOS & Mac indépendant.

#32 Céroce

Céroce

    Mouleur de chocolats

  • Contrôleur d'arômes
  • 5 206 messages
  • LocationSaint-Leu-d'Esserent / France

Posté 03 février 2017 - 12:15

Si, comme Draken on ne veut pas tuer les poneys, on peut toujours utiliser un enum pour l'index :

Je comprends ce que tu cherches à faire, mais comment puis-je l'utiliser en principe ?
Je ne peux plus écrire:

let vec = Vector(x: 1, y: 2, z: 3)
let component = vec[2] // Cannot convert value of type Int to type Vector.Index

RenaudPradenc.com Je suis développeur iOS & Mac indépendant.

#33 Joanna Carter

Joanna Carter

    Broyeur de fèves

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

Posté 03 février 2017 - 12:27

Une idée

struct Vector
{
  enum Index : Int
  {
    case x = 0
    case y
    case z
    
    static let allValues = [x, y, z]
  }
  
  var x: Float
  
  var y: Float
  
  var z: Float
  
  subscript(index: Index) -> Float
  {
    get
    {
      switch index
      {
        case .x : return self.x
        
        case .y : return self.y
        
        case .z : return self.z
      }
    }
  }
}

struct Ray
{
  var origin = [Float]()
		
  var direction = [Float]()
}

struct BoundingBox
{
  let minPoint: Vector
  
  let maxPoint: Vector
  
  func isHitBy(ray: Ray, distMin: Float, distMax: Float) -> Bool
  {
    var tmin = distMin
    
    var tmax = distMax
    
    for component in Vector.Index.allValues
    {
      let invD = Float(1.0) / ray.direction[component.rawValue]
      
      let t0 = (minPoint[component] - ray.origin[component.rawValue]) * invD
      
      let t1 = (maxPoint[component] - ray.origin[component.rawValue]) * invD
      
      tmin = max(tmin, min(t0, t1))
      
      tmax = min(tmax, max(t0, t1))
      
      if tmax <= tmin
      {
        return false
      }
    }
    
    return true
  }
}


#34 Céroce

Céroce

    Mouleur de chocolats

  • Contrôleur d'arômes
  • 5 206 messages
  • LocationSaint-Leu-d'Esserent / France

Posté 03 février 2017 - 13:57

Merci Joanna, je vois mieux.

J'imagine que allValues renvoie une séquence est qu'on peut donc l'indicer si nécessaire. (J'imagine parce que j'ai énormément de mal à trouver les informations dans la doc de Xcode).
RenaudPradenc.com Je suis développeur iOS & Mac indépendant.

#35 Joanna Carter

Joanna Carter

    Broyeur de fèves

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

Posté 03 février 2017 - 14:01

Ce ne devrait pas être nécessaire d'indicer allValues parce que chaque membre est de type Vector.Index, qui contient le rawValue de l'enum.

 

Qu'est-ce que tu crois que tu manque ?



#36 Céroce

Céroce

    Mouleur de chocolats

  • Contrôleur d'arômes
  • 5 206 messages
  • LocationSaint-Leu-d'Esserent / France

Posté 03 février 2017 - 14:28

Pour donner un (mauvais) exemple, si je voulais remplacer ça:
 
for component in 1..<3 {
(donc, seulement y et z)

Ce qui me gêne dans la solution de l'enum, c'est le manque de flexibilité. Mon problème n'est pas de faire le code le plus robuste possible, mais le plus expressif possible.
RenaudPradenc.com Je suis développeur iOS & Mac indépendant.

#37 Joanna Carter

Joanna Carter

    Broyeur de fèves

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

Posté 03 février 2017 - 14:41

Ah! Je pige.

 

Oui, on peut indicer allValues mais pour utiliser les Ints avec le code qui attend les Vector.Index, il faudrait utiliser Vector.Index(rawValue: component) pour convertir l'Int. Mais, là, on aurait le même problème que le rawValue pourrait dépasser les limites.

 

Juste une idée mais, pour BoundingBox, as-tu pensé d'implémenter l'opérateur "Pattern Match" ( ~= ) pour déterminer si un vecteur se trouve là dedans ou non ?



#38 Draken

Draken

    Mouleur de chocolats

  • Artisan chocolatier
  • PipPipPipPipPipPipPipPip
  • 8 585 messages
  • LocationParis

Posté 03 février 2017 - 14:47

Pour donner un (mauvais) exemple, si je voulais remplacer ça:
 

for component in 1..<3 {

 

Cela me hérisse de voir cette syntaxe, avec une valeur finale-1. On dirais du C des années 80.

 

Pourquoi est-ce que tu n'utilises pas la formulation moderne en Swift : 

f

for component in 0...2 {


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/

 

 


#39 Joanna Carter

Joanna Carter

    Broyeur de fèves

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

Posté 03 février 2017 - 14:49

 

Cela me hérisse de voir cette syntaxe, avec une valeur finale-1. On dirais du C des années 80.

 

Pourquoi est-ce que tu n'utilises pas la formulation moderne en Swift : 

f

for component in 0...2 {

 

Car il veut utiliser :

  for component in 1...2

::)



#40 Draken

Draken

    Mouleur de chocolats

  • Artisan chocolatier
  • PipPipPipPipPipPipPipPip
  • 8 585 messages
  • LocationParis

Posté 03 février 2017 - 14:57

Oui, il itére de 1 à 3-1 dans son (mauvais) exemple. Et de 0 à 3-1 dans son vrai code :

struct BoundingBox {
    let minPoint: Vec3
    let maxPoint: Vec3

    func isHitBy(ray: Ray, distMin: Float, distMax: Float) -> Bool {
        var tmin = distMin
        var tmax = distMax
        
        for component in 0..<3 {   // <= ICI, DE 0 à (3-1)
            let invD = Float(1.0) / ray.direction[component]
            let t0 = (minPoint[component] - ray.origin[component]) * invD
            let t1 = (maxPoint[component] - ray.origin[component]) * invD
            tmin = max(tmin, min(t0, t1))
            tmax = min(tmax, max(t0, t1))
    
            if tmax <= tmin {
                return false
            }
        }
        
        return true
    }
}

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/

 

 






Also tagged with one or more of these keywords: Swift, struct, propriétés

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

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