[Haskell-cafe] Are explicit exports and local imports desirable in a production application?

Evan Laforge qdunkan at gmail.com
Fri Sep 18 01:58:05 UTC 2020


On Thu, Sep 17, 2020 at 3:08 PM Isaac Elliott <isaace71295 at gmail.com> wrote:
>
> I don't think that it's unreasonable in general to expect people to explore a codebase via IDE tooling. But given Haskell's current situation on that front, I currently agree with your approach to Haskell imports/exports.
>
> Ignat, I agree with you that explicit imports/exports involve unnecessary typing. I call this "busywork". Explicit exports still seem valuable for encapsulation, avoiding name clashes, and in the case of GHC they unlock a bit more optimisation.
>
> In this case I think that we should automate that busywork, and hopefully the recent Haskell IDE work gives us a path in that direction.

I mention this every time it comes up, but you can automate it right
now, and I've been doing it for the last 10 years or so, no IDE
needed.  The tool I wrote is called fix-imports, but there are a
number of others floating around.  So I don't agree that writing
imports is busywork, you never had to write that stuff in the first
place, if you really didn't want to.

Another benefit of qualifications for navigation is that they can
disambiguate tags.  Fancier IDE-like tools could do that without the
qualification, but tags are here now and I think they actually work
better.  Actually on further thought, the same thing that
disambiguates based on qualification could also easily disambiguate
without it, so maybe this is not a real benefit after all.  I just
happened to set up the former and not the latter :)  My first step
looking at any third-party code is to tags the whole lot but for
whatever reason I still much prefer qualifications.  Few people use
them though.

For explicit exports, I often leave them off for convenience during
development, but put them in when it settles down.  I don't think it
unlocks any optimization in code generation, but it does make rebuilds
faster because it won't change the hi file if you changed a
non-exported non-inlined function.  You also get unused warnings.
When I add the export list, I often append '#ifdef TEST , module
This.Module #endif' so that tests still have total visibility.  I
prefer this to the Internal module approach because I don't like
zillions of modules with the same name, and I don't want to have to
structure code to the whims of tests, and I like to get unused symbol
warnings from ghc without having to go to weeder.

One benefit to explicit exports that surprises me is the trivial
detection of unused functions.  On several occasions I have done extra
work or even just extra thinking to try to preserve a caller, only to
find out that due to the changes I just made, it has no other users
and I could have just deleted it without thinking hard.  Yes, a simple
grep would have revealed that, but I will instantly notice ghc saying
unused symbol and I might not think to insert manual greps into my
planning process.  Often it's a whole chain of callers that can be
deleted, and ghc will find those all immediately.


More information about the Haskell-Cafe mailing list