Pourquoi «!!» est-il considéré comme une mauvaise forme dans Perl?

Lors d’un récent entretien d’embauche, j’ai soumis un exemple de code Perl qui utilisait le soi-disant “secret” !! opérateur . Plus tard, en discutant du code, l’un des enquêteurs m’a demandé pourquoi j’avais choisi d’utiliser ce code, et a indiqué que cela était considéré comme une mauvaise forme. Il n’a pas expliqué pourquoi.

Mon équipe et moi-même utilisons cet opérateur depuis des années, sans jamais réaliser que cela était considéré comme une “mauvaise forme”.

Est-ce que l’opérateur “bang bang” a des effets secondaires ou un comportement inattendu? Pourquoi est-ce, ou pourrait-il être considéré comme “mauvais” par certains? Y a-t-il une alternative idiomatique?

Voici quelques exemples où j’aurais envisagé !! acceptable et / ou souhaitable.

  1. Le code réel dans l’exercice de codage, qui est un exemple d’ajout de valeurs booléennes:

     while (my $line = ) { # snip exists $counts{lines} and $counts{lines} += !! chomp $line; } 
  2. Utiliser une valeur booléenne comme clé de hachage (clairement un exemple simplifié):

     sub foo { my ($input) = @_; my %responses = ( '' => "False", 1 => "True" ); return $responses{ !! $input }; } 
  3. Utiliser un booléen dans une opération au niveau du bit, ou même pack() :

     sub foo { my ( $a, $b, $c ) = @_; my $result = !!$a + (!! $b)<<1 + (!! $c)<<2; return $result; } 
  4. Vous devez effectuer un transtypage à utiliser par une bibliothèque / un processus externe, tel qu’une firebase database, qui considère uniquement certaines valeurs comme véridiques:

     my $sth = $dbh->prepare("INSERT INTO table (flag,value) VALUES (?,?)") $sth->execute("i_haz_cheeseburger", !! $cheeseburger_ssortingng) 

Votre !! profite de deux choses obscures dans Perl: Les valeurs spécifiques que ! renvoie, et que l’une des valeurs possibles est dualvar (un scalaire contenant à la fois une chaîne et un nombre). En utilisant !! aggraver ces comportements est certes épineux. Bien que sa dureté puisse être un énorme avantage, cela peut aussi être un gros avantage. N’utilisez pas de fonctionnalités qui aboutissent à un projet exigeant que “l’utilisation de Perl soit interdite sur ce projet”.

Il y a beaucoup d’alternatives à $count += !! (some_expression) $count += !! (some_expression) pour compter les occurrences des valeurs de vérité de cette expression. L’un est le ternaire, $count += (some_expression) ? 1 : 0 $count += (some_expression) ? 1 : 0 . Cela aussi est un peu obscur. Il existe un moyen compact de faire ce que vous voulez, à savoir utiliser le post-if:

 $x++ if some_expression; 

Cela dit exactement ce que vous faites.

Je l’appellerais «mauvaise forme» parce que ce n’est tout simplement pas nécessaire. Vous n’avez pas besoin de convertir en Perl. Et au mieux, c’est redondant, et au pire, c’est un obscurcissement.

Bien qu’il y ait quelques astuces vraiment intéressantes que vous pouvez utiliser dans Perl, l’un des plus gros problèmes avec le langage (du moins perceptuellement) est qu’il est plutôt enclin à “écrire une fois” le code.

Après tout, pourquoi avez-vous besoin de «doubler» un scalaire pour obtenir un booléen, alors que vous pouvez simplement tester le scalaire?

 my $state = !! 'some_ssortingng'; if ( $state ) { print "It was true\n" }; 

Ou:

 if ( 'some_ssortingng' ) { print "It was true\n" }; 

Et c’est vrai – vous pouvez écrire du code Perl horriblement incompréhensible grâce à des opérateurs “secrets”, des variables basées sur la ponctuation, etc. Et ça marchera bien – par exemple – je considère toujours ce chef-d’œuvre: la source

Mais ce n’est pas un «bon code». Pour un usage “réel”, votre code doit être clair, intelligible et facile à résoudre.

En ce qui concerne les alternatives;

 while (my $line = <$F>) { # snip exists $counts{lines} and $counts{lines} += !! chomp $line; } 

C’est … compter combien de fois vous avez réussi à chomp une ligne je pense? Donc, en gros, il suffit de compter le nombre de lignes dans votre saisie.

Pour cela, je penserais à utiliser $. ‘. À moins que je n’ai rien oublié de votre code?

“Et si ce n’est pas chomp?”

Ok, ça marche. Que diriez-vous:

  $counts{lines}++ if foo(); 

Pour ça:

 sub foo { my ($input) = @_; my %responses = ( "" => "False", 1 => "True" ); return $responses{ !! $input }; } 

J’écrirais cela comme:

 sub foo { my ($input) = @_; return $input ? "True" : "False"; } 

Pour la dernière condition – empaquetant les drapeaux dans un octet:

 sub flags { my @boolean_flags = @_; my $flags = 0; for ( @boolean_flags ) { $flags<<=1; $flags++ if $_; } return $flags; } print flags ( 1, 1, 1 ); 

Ou peut-être si vous faites quelque chose comme ça - en prenant une feuille de la façon dont Fcntl fait en définissant les valeurs à append en fonction de la position, vous n'avez donc pas à vous soucier du problème des arguments positionnels:

Vous pouvez demander que les constantes flock () (LOCK_SH, LOCK_EX, LOCK_NB et LOCK_UN) soient fournies à l'aide de la balise :flock .

Et puis vous pouvez:

 flock ( $fh, LOCK_EX | LOCK_NB ); 

Ils sont définis au niveau du bit, donc ils ajoutent via l'opérateur or - mais cela signifie que c'est une opération idempotente, où le réglage de LOCK_NB deux fois ne le serait pas.

Par exemple,

  LOCK_UN = 8 LOCK_NB = 4 LOCK_EX = 2 LOCK_SH = 1 

Si nous étendons la question au moins subjectif:

Je demande les raisons à éviter !!

  • Perl évalue la "vérité" des variables, il n'y a donc pas vraiment besoin d'un booléen logique réel.
  • Les instructions conditionnelles sont plus claires que leur algèbre booléenne équivalente. if ( $somecondition ) { $result++ } est plus clair que $result += !! $somecondition $result += !! $somecondition
  • C'est sur une liste d'opérateurs secrets parce que c'est obscur. Vos futurs programmeurs de maintenance n’apprécieront peut-être pas cela.
  • !!1 est 1 , !!0 est dualvar('', 0) . Bien que ce soit assez flexible, cela peut surprendre, d'autant plus que la plupart des gens ne savent même pas ce qu'est un dualvar, et encore moins ça ! renvoie un. Si vous utilisez un ternaire, les valeurs que vous obtenez sont explicites: $value ? 1 : 0 $value ? 1 : 0

Toute la question est quelque peu subjective, alors je voudrais donner une opinion différente des autres réponses affichées jusqu’à présent. Je ne considère pas la double négation comme une mauvaise forme en général, mais j’essaierais de l’éviter s’il existe une alternative plus lisible. En ce qui concerne vos exemples:

  1. Utilisez quelque chose comme $count++ if $condition .

  2. Les valeurs de vérité en tant que clés de hachage? C’est tout simplement diabolique. Au moins, il est surprenant pour quiconque doit maintenir votre code.

  3. Ici l’utilisation de !! est justifié.

  4. Ici, j’utiliserais l’opérateur ternaire. Il n’est pas très clair comment execute se comporte quand il est passé par un dualvar.

Une autre situation où il est tout à fait acceptable d’utiliser !! est lors de la conversion de certaines valeurs en booléen, par exemple dans une déclaration de retour. Quelque chose comme:

 # Returns true or false. sub has_item { my $self = shift; return !!$self->{blessed_ref}; } 

La plupart des programmeurs doivent connaître le !! idiome de langages statiquement typés où il est souvent utilisé comme un cast à bool. Si c’est ce que vous voulez faire et qu’il n’y a pas de risque d’effets secondaires indésirables, optez pour la double négation.

Peut-être que ce n’est pas si grave pour le code que vous voyez.

Cependant, votre collègue développeur pourrait le voir un jour corriger un bogue dans votre code et y tomber. Il y a deux options

  1. Il pense que tu as fait une erreur et en enlève une ! , invalider votre code
  2. Il pense que c’est juste la pourriture des logiciels et supprime les deux !! sans une seconde pensée. Après refactoring d’un autre code, il se bloque soudainement … une incompatibilité de type?

Quoi qu’il en soit, cela fera perdre du temps aux futurs développeurs, à moins qu’ils ne le connaissent. Le code intelligent n’est jamais pour vous-même (enfin, cela pourrait aider), mais pour tous ceux qui verront votre code.

Selon l’emploi, c’est une mauvaise forme pour beaucoup de raisons commerciales et d’entrevues

  1. lorsque vous travaillez sur un projet d’équipe, ou tout autre code sur lequel de nombreux autres développeurs pourraient travailler, ne déroulez pas (ou ne suivez pas les règles de l’entreprise)
  2. aller de ce que les sanchises ont dit, cela va causer plus de travail, et ne montre pas clairement les intentions du code.
  3. c’est simplement inutile, et comme nous l’avons vu plus haut – il semble qu’il y ait au moins un scénario où le résultat ne fonctionnerait pas – d’où un bogue.
  4. montrer des utilisations de codage obscur dans une interview, quand il y a un moyen plus facile et plus clair de le faire, cela ne semble pas favorable dans une interview.
  5. une interview est l’endroit où vous voulez montrer que vous êtes un joueur d’équipe, et non pas que vous allez sortir des conneries bizarres que personne d’autre ne comprend (à moins que cela ne soit la réponse à une question non résolue bien sûr)

Il aurait été bon de demander à l’interviewer pourquoi il le considérait comme une “mauvaise forme”. Une astuce de suivi de l’entretien serait de lui envoyer un merci et de lui demander pourquoi il la considère comme une “mauvaise forme”.