TLDR: I made a Julia linter which shows rewrite suggestions online. At the time of writing it analyses 128 Julia repositories (about 1,012,728 lines of code) and shows the diffs.
I was recently watching a video of SourceGraph Campaigns and found it super cool. Basically, it allows you to apply a transformation to many repositories automatically. It would be especially nice if you could rewrite, for example, all occurrences of findfirst(a, b) === nothing to !occursin(a, b).
Anyway, Sourcegraph pointed me to an awesome rewrite tool, namely Comby. For a brief moment, I considered building a replacement for Lint.jl. However, then everyone has to install that tool and keep it updated. So, now I created some rewrite rules, run them over many repositories and show the diffs online. This, for example, can be useful for spotting coding mistakes, make code more readable by simplifying it, and can help in the transition after the release of the new Julia LTS.
@tlienart Thanks! Iāve added an issue for your first suggestion and am going to improve on that. For your second suggestion, I think thatās not possible yet. The site shows too many false positives. So far, I did find some interesting problems in code and created PRs manually:
@Mason thatās not off topic. Are you sure that x === missing is the same as x === nothing? Iām not an expert, so it could definitely be true. Would you mind elaborating a bit more?
respectively, so as far as I can tell, theyāre exactly analogous.
I believe itās usually recommended to use x === nothing and x === missing when possible because the compiler is able to optimize it in more circumstances. From what I understand, ismissing and isnothing are mostly useful for higher order functions, e.g.
I do expect that ismissing(x) is easier to read for new Julia users, and performance is not really the issue for most practical problems (āpremature optimization is the root of all evilā), but you might very well be right that its not an useful pattern to check for. Iām gonna look into it a bit more.
Thatās pretty dope and Iām happy that you analysed two of my repos
How long does it take to produces the results? Is it out of reach to do this for all registered packages?
@joa-quim In response to https://discourse.julialang.org/t/ismissing-x-versus-x-missing/52171/3: Thatās why Iām working ShowLint with the possibility to disable lint patterns in bulk. Instead of adding a lint configuration to each project/repository, I could just disable the check for this pattern and similar checks on all āhigh-performanceā repositories. Basically, the idea is that all the configuration complexity is moved away from the user and is managed at one place. Also, the idea is that its easier for the Julia community to help busy package creators out. For example, some packages are created one or more years ago and the creator has moved on to other things. With something like ShowLint, the community can more easily assist these creators in keeping their packages working and up-to-date.
Haha I didnāt look at the issues though I saw that you changed some a == a in the latest run. Have you tackled the false positives in JuMP.jl for example? There you have @constraint(m, x-1 == 1) and form it into @constraint(m, x-true)
@GunnarFarneback Yes, Iām still tweaking the rules and am note sure what to do with it. I do think that https://github.com/JuliaData/YAML.jl/pull/103 shows that there are situations where that check can be useful but, indeed, its a part of Julia since x == true will give missing if x is a missing.
@Wikunia I got some tips from Rijnard van Tonder (Combyās creator) and expect to have that fixed later today
The replacement for findall(x -> x==false, [true, false]) should probably be findall(!, [true, false]) rather than broadcasting.
But replacing cond == false with cond only seems safe if you are sure that cond::Bool. I donāt see examples where this is clearly violated, but I do have functions which expect either nothing or false. And findall(!, [true, false, nothing]) obviously wonāt work.
Iām afraid that I donāt understand what would be the difference between findall(!, A) and findall(.!A), and why the former would be preferred. Could you explain the difference?
So, this is now the second pattern which doesnāt handle missings well. Thanks for pointing that out