Cognitive Complexity implemented for perl

50 views
Skip to first unread message

Oliver Trosien

unread,
Jan 6, 2017, 7:15:28 PM1/6/17
to SonarQube
Hi,

I read Ann's whitepaper a few days ago, and I must say I was immediately fond of it, so I just implemented it for perl. It's a so-called Perl::Critic rule [1], the perl-based linter tool. Unfortunately the sonar-perl plugin [2] cannot parse perl code yet, so I cannot yet import it as code metric, but only as "code smell". Still...

Alone the part about direct recursion seemed a bit arbitrary to me - given the fact that indirect recursion, the worse part of recursion, cannot be penalized at all. For example, most languages have other ways of iteration, take streams for example. When I announced that I will support the Cognitive Complexity model, I was immediately asked by one of my followers what kind of complexity this piece of code would be:

%params = map { $_, ( param($_) )[0] } grep { lc($_) ne 'submit' } keys param();

You all know that it's very easy to write perl code that is completely incomprehensible, so I wanted to check how the new scoring model works against this code. To the non-perlers, the code would literally translate into something like this in java-land:

Arrays
 .stream(params())
 .filter(p -> {return !"submit".equals(p.toLowerCase()); })
.collect(Collectors.toMap(Function.identity(), p -> params(p));

So, all in all everything but trivial, there's no nesting, and no boolean operators. What I'm saying is maybe the cognitive complexity may be missing on the fact that filter/grep like operations also act like if-else, and stream() is just a different way of iteration. Maybe this needs to be taken into consideration in a future iteration of the scoring.


Regards,
 Oliver

[1] https://metacpan.org/release/OTROSIEN/Perl-Critic-CognitiveComplexity-0.5
[2] https://github.com/otrosien/sonar-perl

G. Ann Campbell

unread,
Jan 9, 2017, 11:23:54 AM1/9/17
to SonarQube, Carlo Bottiglieri
Hi Oliver,

First, this is exciting news! :-D

To answer your point about recursion, new SonarSourcer @Carlo brought up the same point to me - and a whole new way of thinking about it - last week. He agrees with you that this is the worst kind of recursion.

To be honest, I had been thinking that indirect recursion ought to be +1 at the class level but Carlo convinced me instead that each method involved in an indirect recursion cycle should get a recursion increment. (He actually wants to throw in a multiplier or something, but would settle for +1.)

So this is on my ToDo list now. 

In the interests of full disclosure, I should mention that none of our analyzers detect recursion (either kind) yet. 


Regarding your Perl example... it has been a very long time since I did any Perl so thanks for the translation. :-)

I fully understand your point about incomprehensability, but I'm not sure this example falls under Cognitive Complexity. When I was formulating Cognitive Complexity, I did some hard thinking about what should and should not be included, and what I came to was that it should be limited to control flow. For instance multiple levels of pointer indirection can make C code very difficult to understand, but that's about structure and language features, not control flow, so it's ignored by Cognitive Complexity. And so, since your example doesn't seem to contain any control flow (yes, the translation includes lambdas, but they're explicitly exempt) then it's ignored. Unless I've misunderstood something?


Ann

Oliver Trosien

unread,
Jan 10, 2017, 3:23:07 AM1/10/17
to SonarQube, carlo.bo...@sonarsource.com
Hi Ann,

thank you for clarifying. That was what I wanted to know. So, it's all about "structural complexity", and lambdas don't count (can you give a bit more details why you decided so?). I was also wondering, why you would penalize if(condition()) and not  .filter(condition()), but on the other hand, that brings the scoring back towards Cyclomatic Complexity.

BTW: The perl implementation finds recursion patterns, although due to the dynamic nature of the language there might be false positives, and ways to circumvent recursion recognition.

Oliver

G. Ann Campbell

unread,
Jan 10, 2017, 7:29:43 AM1/10/17
to Oliver Trosien, SonarQube, Carlo Bottiglieri
Hi Oliver,

Lambdas are recognized as control flow, just like methods, but they get a pass because they allow you to readably shorthand multiple lines of code into one. 

.filter(), on the other hand, is ignored because it is a method call. Deciding which method calls are "control flow" and which are not is a can of worms I don't want to open.


Ann



---
G. Ann CAMPBELL | SonarSource
Product Manager

--
You received this message because you are subscribed to a topic in the Google Groups "SonarQube" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/sonarqube/963-WZuCmo8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to sonarqube+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/sonarqube/3ea9e4dc-77eb-4274-b9df-5b602fc31071%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages