Are explicit exports and local imports desirable in a production application?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
21 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Are explicit exports and local imports desirable in a production application?

Ignat Insarov
I apologize if this topic has already been clarified elsewhere —
please refer me.

The present message can also be seen _(and answered)_ on the Haskell
Discourse board.[1]

To clarify, an explicit export:

    module X (…) where …

An explicit import:

    import X (…)

## I would like to question the desirability of explicit exports and
local imports in a production application.

I want to make two cases:

* That explicit exports are never necessary. Moreover, that explicit
exports are harmful as they make checking of non-exported definitions
impossible.
* That explicit imports are not necessary when importing a module from
the same package.

By default, I make an easy claim that none are desirable since they
incur mindless typing effort and thereby unfairly tax the programmer.
Let us then consider the justifications for their use despite that.

### Explicit exports.

When there are no explicit exports, everything is exported from a
module. Recall a case when this is disadvantageous: abstract types.
The values of abstract types must only be obtained via smart
constructors. So their definitions should not be made available.
Explicit exports may provide that.

However, there is another practice: putting dangerous definitions of
the supposedly abstract type `X` into a module `X.Internal`, then
importing them to module `X` and defining smart constructors there. By
default, a module only exports the definitions defined in itself —
there are no re-exports. So, a user importing `X` cannot invoke unsafe
constructors from `X.Internal`, and they know better than to import
the dangerous module directly.

In the former case above, the internal definitions remain out of reach
for a test suite. In the latter case, they may be freely checked as
needed.

### Explicit imports.

Recall the scenario in which explicit imports are useful.

* A module `"p" X` from package `p` imports a module `"q" Y` from
package `q v0.0.0`.
* The package `q` bumps the third version number and exports a
definition `Y.d` which name coincides with an already defined
definition `X.d`.

What happens?

  * If imports are explicit, nothing happens. The maintainers of `p`
are safe if they set a restriction as weak as `q ^>= 0.0`.

  * If imports are implicit, there would be a clash of names if `p` is
built against `q v0.0.1`, but the build would pass if it is built
against a less recent version `q v0.0.0.1`.

    The maintainers of `p` might not even notice that the package does
not build in some cases. When they do, they would have to set a
restriction `q ^>= 0.0.0`

But surely there is only one version to build against if the two
modules reside in the same package. So the overlapping names will
necessarily result in an error that would immediately be rectified. It
is no different from any other compile time error.

## Are my considerations fair?

[1]: https://discourse.haskell.org/t/are-explicit-exports-and-local-imports-desirable-in-a-production-application/1411
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Henning Thielemann

On Wed, 16 Sep 2020, Ignat Insarov wrote:

> ### Explicit exports.
>
> When there are no explicit exports, everything is exported from a
> module. Recall a case when this is disadvantageous: abstract types.
> The values of abstract types must only be obtained via smart
> constructors. So their definitions should not be made available.
> Explicit exports may provide that.

You can do the following in Cabal:

Library private
    Exposed-Modules: A.Internal

Library
    Exposed-Modules: A
    Build-Depends: private

Test-Suite foobar-test
    Build-Depends: private

This way you can export the constructors of a datatype from A.Internal and
use them in A and in the test-suite, but the user of your package cannot
access them.

> ### Explicit imports.
>
> Recall the scenario in which explicit imports are useful.
>
> * A module `"p" X` from package `p` imports a module `"q" Y` from
> package `q v0.0.0`.
> * The package `q` bumps the third version number and exports a
> definition `Y.d` which name coincides with an already defined
> definition `X.d`.


I would not distinguish between imports between modules from the same and
from other packages, because in the course of refactoring you might want
to split a package. Instead I write all my modules with qualified imports
in mind, such that I can write e.g. Window.open instead of openWindow.
E.g. 'containers' is a good pattern to follow.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Ignat Insarov
Thank you Henning.

So, the notion of internal libraries amounts to an even stronger
argument in favour of eschewing explicit exports, at least in the case
we consider. Am I reading your implication correctly?

As for qualified imports, I also follow this practice and I think it
is most readable, given that the qualifications are words and not just
letters — alas, using single letter qualifications, such as `T.pack`
for `Data.Text.pack`, is common.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Henning Thielemann

On Wed, 16 Sep 2020, Ignat Insarov wrote:

> So, the notion of internal libraries amounts to an even stronger
> argument in favour of eschewing explicit exports, at least in the case
> we consider. Am I reading your implication correctly?

You need explicit exports in the public interface, in my example module
"A".

> As for qualified imports, I also follow this practice and I think it
> is most readable, given that the qualifications are words and not just
> letters — alas, using single letter qualifications, such as `T.pack`
> for `Data.Text.pack`, is common.

Yes, I prefer Text.pack and Map.union etc.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Ignat Insarov
> You need explicit exports in the public interface, in my example module
> "A".

How so? Consider an example [1]. Building it yields an error, showing
that any unsafe definitions contained in `A.Internal` are out of reach
from another package. I must be missing your point.

[1]: https://github.com/kindaro/exports-and-internal-libraries
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

MarLinn
In reply to this post by Ignat Insarov

> * That explicit exports are never necessary. Moreover, that explicit
> exports are harmful as they make checking of non-exported definitions
> impossible.


It's not just the internal API in the form of constructors that's worth
hiding. What about helper functions? The ones that would be "private" in
an OOP language? Should I rip my logical structure apart just because
exports are tedious?

In fact the OOP separation is a decent framework to reference for
perspective:

public → (explicitly) exported
private → not exported at all
package protected → exported from internal module
protected → not directly controlled by exports, but by types and
available construction paths

All have an equivalent, all are necessary.

But I agree that explicit exports are flawed, because the vast majority
of "stuff" is usually exported. A better way might be to export
everything except explicitly hidden stuff. That's not possible right now
(I think), but imagine syntax like this:

     module Foo (..) hiding ( bar, baz ) where

or

     module Foo (module Foo hiding ( bar, baz )) where

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Henning Thielemann

On Wed, 16 Sep 2020, MarLinn wrote:

> But I agree that explicit exports are flawed, because the vast majority
> of "stuff" is usually exported. A better way might be to export
> everything except explicitly hidden stuff. That's not possible right now
> (I think), but imagine syntax like this:
>
>     module Foo (..) hiding ( bar, baz ) where
>
> or
>
>     module Foo (module Foo hiding ( bar, baz )) where

In Oberon you do not specify an export list, instead you mark exported
identifiers with a star. This way you avoid duplication of identifiers in
the export list and the identifier order is always the order of
definitions in the module.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Henning Thielemann
In reply to this post by Ignat Insarov

On Wed, 16 Sep 2020, Ignat Insarov wrote:

>> You need explicit exports in the public interface, in my example module
>> "A".
>
> How so?

My example should be like so:

module A.Internal where

data T = Private Integer


module A (
    T,  -- do not export constructor
    f,
    ) where

import A.Internal (T(Private))

f :: FooBar
f = do something with Private


You would need the export list in A for exposing T, but not Private.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Olaf Klinke
In reply to this post by Ignat Insarov
Dear Ignat,

have you seen
https://wiki.haskell.org/Import_modules_properly
https://wiki.haskell.org/Qualified_names

I find the arguments convincing. Even in my own packages I sometimes
get lost where a certain function was imported from. When neither
exports nor imports are done explicitly, you usually have only two
choices:
1. search all sources (e.g. with grep -l)
2. rely on the haddock index
Maybe your IDE can do that for you, but you can't expect all downstream
users or all your colleagues to do the same.

-- Olaf

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Georgi Lyubenov
Hard +1 to what Olaf said - this was (still is if I can't get ghcide running) one of the most annoying things when exploring a new codebase for me.

======
Georgi

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Isaac Elliott
In reply to this post by Olaf Klinke
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.

On Fri, 18 Sep 2020, 3:54 am Olaf Klinke, <[hidden email]> wrote:
Dear Ignat,

have you seen
https://wiki.haskell.org/Import_modules_properly
https://wiki.haskell.org/Qualified_names

I find the arguments convincing. Even in my own packages I sometimes
get lost where a certain function was imported from. When neither
exports nor imports are done explicitly, you usually have only two
choices:
1. search all sources (e.g. with grep -l)
2. rely on the haddock index
Maybe your IDE can do that for you, but you can't expect all downstream
users or all your colleagues to do the same.

-- Olaf

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Evan Laforge
On Thu, Sep 17, 2020 at 3:08 PM Isaac Elliott <[hidden email]> 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:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Ignat Insarov
In reply to this post by Henning Thielemann
Thank you Henning. This is true. When one wishes to provide an
abstract type, surely one would like to re-export the type
constructor, but not the associated data constructors — so explicit
exports become unavoidable. I have not accounted for this detail.

> >> You need explicit exports in the public interface, in my example module
> >> "A".
> >
> > How so?
>
> My example should be like so:
>
> module A.Internal where
>
> data T = Private Integer
>
>
> module A (
>     T,  -- do not export constructor
>     f,
>     ) where
>
> import A.Internal (T(Private))
>
> f :: FooBar
> f = do something with Private
>
>
> You would need the export list in A for exposing T, but not Private.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Tom Ellis-5
In reply to this post by Isaac Elliott
On Fri, Sep 18, 2020 at 08:06:14AM +1000, Isaac Elliott wrote:
> I don't think that it's unreasonable in general to expect people to explore
> a codebase via IDE tooling.

Implicit imports prevent people easily understanding code that is
presented on GitHub, for example.  I think this is the main reason I
dislike implicit imports, my own inconvenience coming a close second.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Haskell - Haskell-Cafe mailing list
In reply to this post by Evan Laforge
|  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 <[hidden email]> On Behalf Of Evan
|  Laforge
|  Sent: 18 September 2020 02:58
|  To: Isaac Elliott <[hidden email]>
|  Cc: Olaf Klinke <[hidden email]>; Haskell Cafe <haskell-
|  [hidden email]>
|  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 <[hidden email]> 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&amp;data=02%7C01%7Csimonpj%40microsoft.com%7C722f388e97ba432419d308d85b
|  7673dd%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637359911600724047&amp;s
|  data=M4h%2F%2FjCg7iLdpoIYrgcThIMAtCRNdlYSdbPW%2BtDXKV0%3D&amp;reserved=0
|  Only members subscribed via the mailman list are allowed to post.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Ignat Insarov
I would like to summarize the conversation so far. Surely I am not
free from bias, so please object if my representation of some of the
opinions I am re-stating is unfair or incomplete to their
disadvantage. I shall present arguments and counter-arguments in the
shape of a tree, with markup and indentation.

### Many people said that they like qualified imports.
Note that my opening message did not speak against that. I suppose I
should have stated openly that I am all for appropriate use of
qualified imports with descriptive names, such as `Text.pack`,
`Set.fromList` and even `List.sort` — although `Maybe.fromMaybe` may
be be too much. I think there is wide agreement about this.

## Imports.

### Reasons why explicit imports may be preferable:
* Resolution of names to the originating modules.
  - Note that this still leaves it to the reader to resolve modules to
packages. That is, unless one also insists on using package imports,
which I see very rarely.
  - Modern tools can resolve names as if by magic, qualified or not.
Surely we can expect more progress in this direction.
    * Can we expect online, multilingual code repositories to do this for us?

### Cases when explicit imports are required:
None so far. _(Disambiguation can be done with qualified imports.)_

## Exports.

### Reasons why explicit exports may be preferable:
* There may be a helper function that is used by several exported
functions, so it cannot be put in a `where` clause — if it is absent
from the explicit export list, GHC will be able to optimize better.
* Haddock magic: changing the order of exports, adding headers and sections.
  - Most if not all of these effects can be accomplished without export lists.
* Detection of dead code by GHC.
  - Tools exist to detect dead code without the use of explicit exports.

### Cases when explicit exports are required:
* Exporting the type constructor of an abstract type, but not its data
constructors.
* Re-exporting modules.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Evan Laforge
In reply to this post by Haskell - Haskell-Cafe mailing list
On Fri, Sep 18, 2020 at 12:48 AM Simon Peyton Jones
<[hidden email]> wrote:
>
> |  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

I stand corrected!

I recall reading somewhere that, for the purposes of inlining, all
symbols inside the module are fully visible, so the only difference
the export makes is whether or not the non-inlined/specialized version
is also kept around for possible external callers.  So maybe that's
just wrong, or I made it up somehow, or maybe it's right but just for
inlining and not for those other things?

I suppose it could theoretically have been right if GHC were willing
to duplicate all exported functions and perhaps analyze them twice,
but perhaps it's not willing to do that?  I'm not saying it should,
especially if it would hurt compile time, just curious.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Haskell - Haskell-Cafe mailing list
|  I suppose it could theoretically have been right if GHC were willing
|  to duplicate all exported functions and perhaps analyze them twice,
|  but perhaps it's not willing to do that?  I'm not saying it should,
|  especially if it would hurt compile time, just curious.

For non-exported functions, GHC inlines one regardless of size (and discards the definition) if it has exactly one occurrence, because that doesn't duplicate.   For all other functions (local and exported) GHC will inline (and hence duplicate) small ones, and not inline (thereby avoiding duplicating) big ones.

There are flags to control what "big" means.

Does that answer your question?

Simon


|  -----Original Message-----
|  From: Evan Laforge <[hidden email]>
|  Sent: 21 September 2020 01:27
|  To: Simon Peyton Jones <[hidden email]>
|  Cc: Isaac Elliott <[hidden email]>; Olaf Klinke <olf@aatal-
|  apotheke.de>; Haskell Cafe <[hidden email]>
|  Subject: Re: [Haskell-cafe] Are explicit exports and local imports
|  desirable in a production application?
|  
|  On Fri, Sep 18, 2020 at 12:48 AM Simon Peyton Jones
|  <[hidden email]> wrote:
|  >
|  > |  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
|  
|  I stand corrected!
|  
|  I recall reading somewhere that, for the purposes of inlining, all
|  symbols inside the module are fully visible, so the only difference
|  the export makes is whether or not the non-inlined/specialized version
|  is also kept around for possible external callers.  So maybe that's
|  just wrong, or I made it up somehow, or maybe it's right but just for
|  inlining and not for those other things?
|  
|  I suppose it could theoretically have been right if GHC were willing
|  to duplicate all exported functions and perhaps analyze them twice,
|  but perhaps it's not willing to do that?  I'm not saying it should,
|  especially if it would hurt compile time, just curious.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Evan Laforge
On Mon, Sep 21, 2020 at 12:41 AM Simon Peyton Jones
<[hidden email]> wrote:

>
> |  I suppose it could theoretically have been right if GHC were willing
> |  to duplicate all exported functions and perhaps analyze them twice,
> |  but perhaps it's not willing to do that?  I'm not saying it should,
> |  especially if it would hurt compile time, just curious.
>
> For non-exported functions, GHC inlines one regardless of size (and discards the definition) if it has exactly one occurrence, because that doesn't duplicate.   For all other functions (local and exported) GHC will inline (and hence duplicate) small ones, and not inline (thereby avoiding duplicating) big ones.
>
> There are flags to control what "big" means.
>
> Does that answer your question?

Yes I think it does, to rephrase, we could say the distinction is not
so much exported or not, but 1 caller vs. >1 caller.  But of course it
happens that exported forces you to assume >1 caller.

I was thinking GHC could theoretically be willing to duplicate an
exported oversized function if it only occurs once within the module,
because this is a max of 1 additional copy, not an unbounded number.
But perhaps it makes sense that it refuses to copy at all if it's over
the size limit, because who's to say how far over the limit it is!
Inlining something with exactly 1 caller is guaranteed safe.  It also
makes it worry-free to extract an expression to a where, or promote a
where to the toplevel, so long as it remains called only once.  This
is as it should be, but it's nice to know for sure!
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: Are explicit exports and local imports desirable in a production application?

Henning Thielemann
In reply to this post by Isaac Elliott

On Fri, 18 Sep 2020, Isaac Elliott 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.

I already lost many hours exploring orphaned codebases. Imagine a five
year old package or say ten years that you cannot compile anymore. You do
not know with what version of GHC it worked, and even if you would know,
you will not be able to get this GHC version running anymore. You do not
know which library versions the package used, because Build-Depends is
missing version ranges. Even if you would know, you would not be able to
get old library versions compiled with new GHC versions anymore. This
orphaned package uses identifiers like "prim" and you have to search
whether this is a local identifier or whether it is external and then from
which package? No IDE will help with code that misses so many information.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
12