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

Simon Peyton Jones simonpj at microsoft.com
Fri Sep 18 07:48:11 UTC 2020


|  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

Actually, it does make a difference to optimisation.  If a function is known not to be exported, then GHC knows every one of its call sites.  Eg so

* It may be called only once, and can be inlined (regardless of size)
  at that call site.

* If we get a worker/wrapper split, we'll inline the wrapper at all the
  call sites.  If it's not exported, GHC can discard the wrapper.

* CalledArity analysis can be much more aggressive when it can see all
  call sites.

I don't know anyone who has measured the perf or binary-size benefits of limiting export lists. It's probably not huge.  But it's not zero.

Simon


|  -----Original Message-----
|  From: Haskell-Cafe <haskell-cafe-bounces at haskell.org> On Behalf Of Evan
|  Laforge
|  Sent: 18 September 2020 02:58
|  To: Isaac Elliott <isaace71295 at gmail.com>
|  Cc: Olaf Klinke <olf at aatal-apotheke.de>; Haskell Cafe <haskell-
|  cafe at haskell.org>
|  Subject: Re: [Haskell-cafe] Are explicit exports and local imports desirable
|  in a production application?
|  
|  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.
|  _______________________________________________
|  Haskell-Cafe mailing list
|  To (un)subscribe, modify options or view archives go to:
|  https://nam06.safelinks.protection.outlook.com/?url=http%3A%2F%2Fmail.haskel
|  l.org%2Fcgi-bin%2Fmailman%2Flistinfo%2Fhaskell-
|  cafe&data=02%7C01%7Csimonpj%40microsoft.com%7C722f388e97ba432419d308d85b
|  7673dd%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637359911600724047&s
|  data=M4h%2F%2FjCg7iLdpoIYrgcThIMAtCRNdlYSdbPW%2BtDXKV0%3D&reserved=0
|  Only members subscribed via the mailman list are allowed to post.


More information about the Haskell-Cafe mailing list