I'm not sure we already have something similar, but I'm working on more code inspections for the IntelliJ plugin and it's always a good idea to ask the community. Since it doesn't really fit on main, I'm posting it here on Meta.
Linting is an excellent way to point the developer to probable errors that he might have overlooked. With a dynamic language like the one of Mathematica, we are a bit restricted with what we can do, since we cannot evaluate code and since most things require evaluation to be sure if they are a bug or not. Nevertheless, there are checks we can do. For instance If[a=b, ..]
is most likely a bug and even if the developer knew what he did, it is a bad style.
There are trickier examples like If[a<5,...]
. This looks okay but knowing that a<5
stays unevaluated if the comparison cannot be done, it is a source of error because you end up with the unevaluated If
expression in your wrong result and debugging might be complicated.
In both examples, wrapping TrueQ
around the condition resolves the issue and although there might still be a bug, at least you can be sure your If
expression is evaluated to some branch.
Other common sources of error are, e.g. x_?testFunc[#]&
or implicit multiplication through linebreaks.
Question: What are common bugs in your code and could they have been pointed out by a linter? If you like to share your thoughts, please provide one issue per answer, so that others can vote. I'm looking forward to your suggestions and see if I can implement some of them in IntelliJ.
Example issue: With the alternative layout for packages which was pointed out by Leonid, we can use directives for a static code analyzer to easily export symbols or declare them as package symbols. As Leonid pointed out, the directives need to be on their own source-line with nothing else on it. So for the directives
PackageScope["myFunc"]
PackageExport["MyExportedFunc"]
I implemented the following rules
- They need to be on their own source line with nothing else on it
- Their string argument must be a valid identifier
::usage
message starts with the name of the symbol it's being defined for or something)sqrt
detected? These seem to slip in out of habit for even non-novice Mathematica users from what I have observed.posVec_List ? AllTrue[Positive]
The intention is to write a pattern for a vector containing all positive numbers. But?
actually binds even tighter than[ ... ]
! It must be written asposVec_List ? (AllTrue[Positive])
. I do not fall forx_?testFunc[#]&
anymore but I did fall for this one a few times.sqrt
yourself, then this will always trigger a warning.Slot
-arguments, like#^2& /@ Join[#,#]&
. Many people would prefer to turn such an inspection off, and even those of us who strive to never write such code might rarely benefit from it (as it's relatively easy to avoid doing this). It might be useful when refactoring others' code (I think @Kuba does that a lot). I'd suggest low priority if you consider it at all.