Re-exposing Types

First: This issue has been brought up in the github issue tracker, but feature requests are now all closed there. This issue has been brought up here, but since I didn’t see it months ago, the 10-day inactivity timer closed discussion on that item… So, I bring it up again, since I have no other way to comment.

When building larger libraries (or even larger applications), often you need to partition your code so that you have a set of files like:

CoolLib.elm
CoolLib/Internal/ThingA.elm
CoolLib/Internal/ThingB.elm
CoolLib/Internal/Types.elm

You want clients to only import CoolLib. If the core types of the package are in CoolLib.Internal.Types, you can generally reexpose them in CoolLib as needed, except for algebraic types:

module CoolLib.Internal.Types exposing
  ( CoolTypeA
  , CoolTypeB(..)
  , coolFunc
  )

type alias CoolTypeA = { foo : Int, bar : String }
type CoolTypeB
  = Solo Float
  | Bond Bool
  | Ripley String

coolFunc : CoolTypeA -> CoolTypeB -> Maybe Int
coolFunc a b = ...

and

module CoolLib exposing
  ( CoolTypeA
  , CoolTypeB(..)
  , coolFunc
  ...
  )

import CoolLib.Internal.Types as Types

type alias CoolTypeA = Types.CoolTypeA -- this is fine

-- there is no way to do the same for CoolTypeB and its constructors

coolFunc : CoolTypeA -> Maybe Int
coolFunc = Types.coolFunc  -- this is fine

It seems like it wouldn’t be all that hard to come up with a syntax for this.

type alias CoolTypeB(..) = Types.CoolTypeB(..)

would be one such option…

I realize that currently, the work around is to create a second matching type in the top module, and then map back and forth between them. Aside from the inefficiency of doing so, once the public API of the package is moderately size, this becomes a large coding burden. It becomes even more complex if the type is used inside a record:

type Status = Dead | Phantom | Alive
type alias CoolThing =
  { blahblah : List String
  , woofwoof : Dict String Status
  } 

because now you need a public version of the record type as well.

I understand in past discussions, there has been concern about re-exposing such types from one package out in another. In my experience in Elm (and other similar languages) the vast majority of the time you want to do this is like the case above: Re-exposing a type from a “lower” module in a package to the package’s type file. It seems like it would be acceptable to require that such re-exposes happen only intra-package.

4 Likes