Veuillez contribuer à la discussion ci-dessous
[ ] Conventions de dénomination des variables (VAR, VAR_INPUT, VAR_OUTPUT, VAR_IN_OUT, VAR_INST, TEMP)
@mark-lazarides @Roald87 @philippleidig @jozefchmelar gardons la discussion sur les conventions ici... détendez-vous pour une conversation rapide ; discussions ici pour suivre l'activité
À mon avis, les propriétés doivent être définies comme suit "IsEnabled". Le nom lui-même devrait déjà indiquer de quel type il s'agit.
J'aime la valeur de retour de la méthode en tant que booléen. Je trouve les types de données plus complexes inappropriés, car ils doivent être instanciés à l'extérieur ou renvoyés par référence.
L'héritage de chaque classe de base de "fbComponent" est-il nécessaire pour utiliser Inxton ou tc.prober ?
En ce qui concerne la dénomination des types, je suis personnellement un peu radical et omet généralement les préfixes. Sauf pour les interfaces, les références et les pointeurs.
par exemple
Dénomination des types
| Type de bloc | notation | Préfixe | Exemple |
| :------------- | :--------- | :------------ | :-------------------------------------------------------------- -- |
| Nom FB/CLASSE | PascalCas |Non | Cyclinder
|
| Nom du type ENUM | PascalCas |Non | MachineState.Start
|
| Nom INTERFACE | PascalCase | I
| ICyclinder
|
| Nom de la FONCTION | PascalCas |Non | Add()
|
| Nom STRUCT | PascalCase | Non | Data
|
| nom UNION | PascalCase | Non | Control
|
@philippleidig
- À mon avis, les propriétés doivent être définies comme suit "IsEnabled". Le nom lui-même devrait déjà indiquer de quel type il s'agit.
Complètement d'accord.
- J'aime la valeur de retour de la méthode en tant que booléen. Je trouve les types de données plus complexes inappropriés, car ils doivent être instanciés à l'extérieur ou renvoyés par référence.
Nous l'utilisons comme décrit avec nos composants. C'est utile pour contrôler l'état d'une séquence. Dans la grande majorité des cas boo suffit. Parfois, ce serait bien d'avoir plus d'informations sur l'état de la méthode ... mais cela nécessiterait une discussion plus large (peut-être une syntaxe fluide comme quelque chose)
- L'héritage de chaque classe de base de "fbComponent" est-il nécessaire pour utiliser Inxton ou tc.prober ?
Non, il n'y a pas d'exigence spécifique pour cela, ni Inxton ni tc.prober. Nous l'utilisons de cette manière. ComponentBase
est une classe abstraite qui a un contrat public (méthode manuelle, etc.), mais elle peut implémenter certaines fonctionnalités communes pour les composants. Je ne suis pas un grand fan de l'héritage (je préfère la composition), mais dans ce cas, j'aimerais avoir une option ouverte pour l'avenir.
Dans inxton, si vous souhaitez collecter tous les composants d'une collection, vous pouvez le faire lorsqu'il existe something is copmonent
mécanisme pour cela.
Il y a aussi une autre raison à cela. Nous travaillons ces jours-ci sur l'open source de notre bibliothèque de base, qui a certaines exigences en ce qui concerne. J'espère pouvoir proposer quelque chose la semaine prochaine. Pour vous donner plus de détails.
- En ce qui concerne la dénomination des types, je suis personnellement un peu radical et omet généralement les préfixes. Sauf pour les interfaces, les références et les pointeurs.
par exempleDénomination des types
Type de bloc Notation Préfixe Exemple
Nom FB/CLASS PascalCase NonCyclinder
Nom du type ENUM PascalCase NonMachineState.Start
Nom de l'INTERFACE PascalCaseI
ICyclinder
Nom de la FONCTION PascalCase NonAdd()
Nom STRUCT PascalCase NonData
Nom UNION PascalCase NonControl
Pas fan des préfixes non plus. Le tableau ressemble au système de préfixes que nous utilisons... mais encore une fois, si nous décidions de nous en débarrasser, cela me rendrait tout simplement heureux.
Dans la plupart des cas, je ne vois pas d'avantage à utiliser des préfixes. Je suis d'accord avec la proposition de @philippleidig .
Je dirais que le pointeur et la référence sont une exception ici.
J'ai proposé mes conventions dans PR #5
Je ne vois pas d'avantage à utiliser le préfixe. Cela ne m'aide en rien.
Les variables de membre de classe (FB) doivent être masquées et commencer par un petit nom
~ PascalVAR{attribut 'masquer'}déclencheur : BOOL ;{attribut 'masquer'}compteur : INT;{attribut 'masquer'}analogStatus : AnalogStatus;END_VAR~
@jozefchmelar
Dans la plupart des cas, je ne vois pas d'avantage à utiliser des préfixes. Je suis d'accord avec la proposition de @philippleidig .
Je dirais que le pointeur et la référence sont une exception ici.
👍
J'ai proposé mes conventions dans PR #5Dénomination des membres et dénomination du type
Je ne vois pas d'avantage à utiliser le préfixe. Cela ne m'aide en rien.
👍👍Variables membres
Les variables de membre de classe (FB) doivent être masquées et commencer par un petit nom
VAR {attribute 'hide'} trigger : BOOL; {attribute 'hide'} counter : INT; {attribute 'hide'} analogStatus : AnalogStatus; END_VAR
trigger
(nom de variable) et Trigger
(nom de propriété) seraient en conflit. Nous devrons le préfixer avec _
comme proposé, je supposeEntièrement d'accord 👍
Il y a aussi l'attribut "conditionalshow". Mais cela ne peut être utilisé qu'en conjonction avec une bibliothèque compilée.
https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/8095402123.html &id=7685156034373049758
Puisque je suppose que nous fournirons une bibliothèque ouverte, cela n'aurait qu'un sens limité.
_
comme préfixe pour les variables membres est nécessaire comme l'a dit @PTKu .
J'aime généralement m'en tenir aux conventions de dénomination et à la sélection de noms de C#.
J'aime la valeur de retour de la méthode en tant que booléen. Je trouve les types de données plus complexes inappropriés, car ils doivent être instanciés à l'extérieur ou renvoyés par référence.
@philippleidig qu'entendez-vous par valeurs de retour ? Dans ce cas, ils sont utilisés comme contrôles d'erreurs ? Habituellement, la valeur de retour dépend de la méthode. CalculcateArea
renverrait un REAL
`LREAL`.
Entièrement d'accord sur la dénomination de variable suggérée !
J'aime la valeur de retour de la méthode en tant que booléen. Je trouve les types de données plus complexes inappropriés, car ils doivent être instanciés à l'extérieur ou renvoyés par référence.
@philippleidig qu'entendez-vous par valeurs de retour ? Dans ce cas, ils sont utilisés comme contrôles d'erreurs ? Habituellement, la valeur de retour dépend de la méthode.
CalculcateArea
renverrait unREAL``LREAL
.
@ Roald87 l'idée serait que la méthode d'un composant qui exécute une action renverrait 'true' lorsque l'action est terminée (MoveToHome() lorsque le capteur/position d'origine est atteint). Cela n'empêche pas d'autres types de retour si nécessaire.
Entièrement d'accord sur la dénomination de variable suggérée !
J'aurais une suggestion sur les tableaux. Il existe une exigence formelle pour le compilateur inxton qui transpile uniquement les tableaux basés sur 0. La raison est d'éviter la confusion lorsqu'il est utilisé en C#.
_array : TABLEAU[0..10] DE BOOL ; // trans-piles
tandis que
_array : TABLEAU[1..10] DE BOOL ; // ne trans-empile pas
Un commentaire à ce sujet ?
Idem pour TwinCAT HMI (TE2000)
Idem pour TwinCAT HMI (TE2000)
Ce serait très pratique d'avoir les tableaux synchronisés avec l'IHM en effet !
@philippleidig || @ Roald87 est -ce que l'un d'entre vous aurait des conventions de relations publiques sur les tableaux, alors s'il vous plaît ... J'aime juste voir plus de contributeurs dans le dépôt :).
J'aurais une suggestion sur les tableaux. Il existe une exigence formelle pour le compilateur inxton qui transpile uniquement les tableaux basés sur 0. La raison est d'éviter la confusion lorsqu'il est utilisé en C#.
_array : TABLEAU[0..10] DE BOOL ; // trans-piles
tandis que
_array : TABLEAU[1..10] DE BOOL ; // ne trans-empile pasUn commentaire à ce sujet ?
En raison du fonctionnement de la boucle de texte structuré, je préfère conserver les tableaux PLC dimensionnés 1..X. Le code est ainsi plus facile à lire partout dans l'automate. Je pense que nous devrions toujours écrire du code attrayant et maintenable sur l'automate. Si nous avons besoin de shims pour que cela fonctionne mieux sur des morceaux de code tiers, nous pouvons les gérer séparément.
// Declaration
NUMBER_OF_DRIVES : INT := 10;
drives : ARRAY[1..NUMBER_OF_DRIVES] OF I_Drive;
// now in the code
FOR i := 1 to NUMBER_OF_DRIVES DO
drives[i].SomethingCool();
END_FOR
// Compared to
// Declaration
drives : ARRAY[0..(NUMBER_OF_DRIVES -1) ] OF I_Drive;
// Code
FOR i := 0 to (NUMBER_OF_DRIVES -1) DO
drives[i].SomethingCool();
END_FOR
J'aime la valeur de retour de la méthode en tant que booléen. Je trouve les types de données plus complexes inappropriés, car ils doivent être instanciés à l'extérieur ou renvoyés par référence.
Je pense que les méthodes devraient retourner ce qui est raisonnable pour la méthode. Le nom de la méthode devrait vous aider à comprendre cela.
c'est à dire
IF NOT piece.PassesValidation() THEN
LogError('Piece does not pass validation');
END_IF
// OR
IF sequence.Finished THEN
axis.Disable(); // No return type necessary.
state := WaitForAxisDisabled;
END_IF
@ Roald87 l'idée serait que la méthode d'un composant qui exécute une action renverrait 'true' lorsque l'action est terminée (MoveToHome() lorsque le capteur/position d'origine est atteint). Cela n'empêche pas d'autres types de retour si nécessaire.
Je n'aime vraiment pas l'approche consistant à appeler à plusieurs reprises une méthode publique, où cette méthode exécute la fonctionnalité à plusieurs reprises jusqu'à ce qu'elle soit correcte. Il y a un seul cas, je pense que c'est acceptable (s'il y a une méthode de type "Execute" sur une interface, mais il y a aussi de meilleures façons pour que cela fonctionne aussi, je crois).
Les problèmes avec cela;
atEnd := axis.GoToEnd();
atBeginning := axis.GoToBeginning();
@philippleidig ne connaît pas TwinCAT HMI. Comment les tableaux non basés sur 0 sont-ils gérés ici ?
@mark-lazarides
Je pense que les méthodes devraient retourner ce qui est raisonnable pour la méthode. Le nom de la méthode devrait vous aider à comprendre cela.
👍
La concurrence et les conditions de concurrence sont toutes des préoccupations raisonnables. À mon humble avis, ces problèmes doivent être résolus autant que possible au niveau des composants, mais surtout au niveau de la coordination lors de la consommation des composants. Les méthodes de composant doivent être appelées à partir de primitives de type contrôleur d'état correctement implémentées (qu'il s'agisse de simples CASE, IF, ELSIF ou d'un séquenceur/sélecteur/itérateur plus complexe) qui empêcheraient les appels simultanés de méthodes en conflit de la même instance d'un composant .
Quelque chose comme ça devrait être empêché dans le code consommateur du composant
~atEnd := axe.GoToEnd();atBeginning := axe.GoToBeginning();~
Le executing methods
retournant true
fois terminé permet une utilisation déclarative propre.
Ce que j'ai en tête, c'est quelque chose comme ça :
~~~
VAR
_état : INT ;
CAS _état DE
0 :
SI(axe.MoveAbsolute(Position : 100.0)) ALORS
_état := 1;
FIN SI;
1:
SI(axe.MoveRelative(Position : 100.0)) ALORS
_état := 2;
FIN SI;
2 :
SI(axe.MoveAbsolute(Position : 300.0)) ALORS
_état := 3;
FIN SI;
3 :
_état := 0;
END_CASE
~~~
Celle-ci pourrait être réduite à
~~~
VAR
_état : INT ;
CAS _état DE
0 :
Attendre(axis.MoveAbsolute(Position : 100.0),1);
1:
Attendre(axis.MoveRelative(Position : 100.0),2);
2 :
Attendre(axis.MoveAbsolute(Position : 300.0),3);
3 :
Attendre(vrai,0);
===================================
MÉTHODE Attendre
VAR_INPUT
fait : BOOL
nextState : INT;
END_VAR
SI (fait) ALORS
_state := nextState;
~~~
edit: je suppose que le composant est utilisé dans une seule tâche plc
Cela impose des contraintes sur la consommation du code. Nos composants ne doivent pas être sujets à des erreurs si le consommateur les utilise dans une commande incorrecte. Ils doivent bien réagir à toutes les interactions. Ils ne "fonctionneront" pas nécessairement (c'est-à-dire qu'appeler res := axis.MoveTo(Position:=100);
avant axis.Enable()
ne fonctionnerait pas), mais le code consommateur doit recevoir suffisamment d'informations à tous les points pour comprendre d'où vient le problème.
Il ne se lit toujours pas bien pour moi non plus. Vous ne pouvez pas lire axis.MoveAbsolute(syx) et comprendre qu'il doit être appelé de manière cyclique. Vous ne comprendriez que si vous saviez que notre style idiomatique exigeait cela de vous et à ce stade, je pense que nous avons échoué à créer quelque chose de très utilisable.
Je dirais également que, que les erreurs puissent ou non être factorisées, elles sont encore plus probables. Avec l'approche d'appel de méthode cyclique, vous pouvez créer une méthode qui vérifie si l'état de l'objet est prêt à être appelé, puis appeler la méthode cyclique, puis surveiller l'autre état de l'objet pour s'assurer que rien ne s'est passé entre-temps. Ou vous faites la demande, qui vous indique si elle a réussi ou non, puis surveillez l'état de l'achèvement. Vous pouvez enregistrer un rappel pour cela dans le cadre de la demande si vous le souhaitez, ce qui est une approche OO décente et réduit davantage les appels / interrogations de manière cyclique.
@mark-lazarides correct ! I execute methods
(appelons-les ainsi) ne devrait pas implémenter de logique cyclique. J'ai supposé ce dont nous avons discuté précédemment que nous nous assurons que ce qui doit être exécuté de manière cyclique serait placé soit dans le corps de FB, soit dans une méthode Cyclic
; qui devrait être appelé à un endroit approprié dans le programme du consommateur.
D'ACCORD. Alors pourquoi appelons-nous la méthode de manière cyclique ? Je pense toujours que les arguments originaux tiennent. La méthode devrait faire un travail. Commencez quelque chose (et donc signalez le succès de cela) ou obtenez quelque chose (et retournez-le).
D'ACCORD. Alors pourquoi appelons-nous la méthode de manière cyclique ? Je pense toujours que les arguments originaux tiennent. La méthode devrait faire un travail. Commencez quelque chose (et donc signalez le succès de cela) ou obtenez quelque chose (et retournez-le).
Aucune objection Mark, nous n'avons pas besoin d'appeler les méthodes d'exécution de manière cyclique, mais cela ne devrait pas être un problème si nous le faisons.
Je ne vois pas pourquoi une méthode ne pourrait pas renvoyer le résultat de l'opération.
Je pense que nous devrions proposer des composants plus complexes et pour prototyper ces idées (le piston pneumatique n'est pas assez complexe pour cette discussion), je pense que nous pourrions commencer par l'entraînement/l'axe.
D'accord, Pierre.
En raison du nom du fil, je pensais que nous visions cela comme une convention ! Toutes mes excuses si j'ai mal compris.
Chris a un bloc d'axe de base en tant que PR pour le moment - je l'ai commenté, mais il a besoin de plus d'attention.
@mark-lazarides aucune excuse nécessaire Mark, nous sommes ici pour discuter librement, je jetterai un œil aux relations publiques demain...
@philippleidig @Roald87 @dhullett08 Discussion sur la conception des composants également ici
Quelques suggestions aléatoires tirées des documents PLCopen.
plcopen_coding_guidelines_version_1.0.pdf
Constantes
Doit être en MAJUSCULES pour être facilement identifiable
Longueur de nom acceptable
Minimum de 4 caractères maximum de 24 caractères ?
Quelques suggestions aléatoires tirées des documents PLCopen.
Merci pour le lien
Constantes
Doit être en MAJUSCULES pour être facilement identifiable
👍
Longueur de nom acceptable
Minimum de 4 caractères maximum de 24 caractères ?
Les noms plus longs ne devraient pas poser de problème jusqu'à ce qu'ils expriment l'intention, 24 caractères devraient suffire, mais je ne mettrais pas de limite à max. personnages. Les noms trop courts sont en effet suspects ils doivent faire plus de 4 caractères.
@Seversonic vos remarques ajoutées au document...
discussion suite ici #11
Je n'aime vraiment pas vos conventions mais je pense que votre projet est assez intéressant !
perso je préfère une manière plus classique
Bloc fonction FB_ fb
Méthode M_Add()
P_Paramètre Prop
Salut, @PeterZerlauth et merci. C'est un peu laborieux de se mettre d'accord sur les conventions car on est à mi-chemin entre l'automate et le génie logiciel classique.
Voici le sondage du début des discussions :
En plus de cela, il y a eu une discussion ici et dans la chaîne Slack, il pourrait aussi y avoir quelque chose dans le repo @ dhullett08 TcOpen.
Il y avait un sentiment général (ou du moins je l'interprète de cette façon) que nous devrions abandonner les préfixes s'ils ne fournissent pas d'informations utiles ou si l'IDE moderne fournit les informations que nous transmettions avec les préfixes dans le passé.
Je comprends qu'il s'agit de préférences personnelles et qu'il n'y a vraiment pas de bonne ou de mauvaise façon de le faire. Faut juste qu'on s'entende sur quelque chose.
Clôturant ici, la discussion se poursuit ici : https://github.com/TcOpenGroup/TcOpen/discussions/11
Commentaire le plus utile
J'aurais une suggestion sur les tableaux. Il existe une exigence formelle pour le compilateur inxton qui transpile uniquement les tableaux basés sur 0. La raison est d'éviter la confusion lorsqu'il est utilisé en C#.
_array : TABLEAU[0..10] DE BOOL ; // trans-piles
tandis que
_array : TABLEAU[1..10] DE BOOL ; // ne trans-empile pas
Un commentaire à ce sujet ?