Abstract FilePath Proposal

Herbert Valerio Riedel hvriedel at gmail.com
Sat Jun 27 13:37:04 UTC 2015

On 2015-06-27 at 14:56:33 +0200, David Fox wrote:


> ​I've had success with a slightly different "How":

What was your concrete use-case btw?

> Phase 1: Replace FilePath with a type class, with instances for the old
> FilePath (i.e. String) and the new implementation.

what would that comprise in the FilePath case?

I assume adding a transitional class whose methods are not exposed (and
whose typeclass name is exported from some GHC-specific internal-marked
module)? i.e.

  class IsFilePath a where
    privateToFilePath :: a -> FilePath
    privateFromFilePath :: FilePath -> a
  instance IsFilePath FilePath where
    privateToFilePath   = id
    privateFromFilePath = id
  instance IsFilePath [Char] where
    privateToFilePath   = System.IO.toFilePath
    privateFromFilePath = System.IO.fromFilePath


as well as changing a lot of type-sigs in base & filepath from

  writeFile :: FilePath -> String -> IO ()
  openTempFile :: FilePath -> String -> IO (FilePath, Handle)


  writeFile    :: IsFilePath a => a -> String -> IO ()
  openTempFile :: IsFilePath a => a -> String -> IO (a, Handle)


> Phase 2:  Wait until a suitable amount of hackage builds without the string
> instance.

I can see Stackage helping with that by using a custom GHC which lacks
the legacy `IsFilePath [Char]`-instance. So I'd be optimistic that Phase2 could be
accomplished within one year for the Stackage-subset of Hackage.

> Phase 3: Deprecate the String instance - move it to an old-filepath package.
> Phase 4: Replace the type class with the new implementation

I assume this means getting rid again of the typeclass, and changing the
type-sigs back to i.e.

  writeFile :: FilePath -> String -> IO ()
  openTempFile :: FilePath -> String -> IO (FilePath, Handle)
(but now with with the new opaque `FilePath`)?

> This way the new implementation is available immediately, packages can
> begin converting at once, benefits can be assessed.

This scheme seems feasible at first glance, as long as the typeclass
doesn't start spreading across packages and find its way into type-sigs
(in which case it'd become more disruptive to get rid of it
again). Otoh, I'm not sure (assuming I understood how your scheme works)
it can be avoided to have the typeclass spread, since if not every API
that now has `FilePath` arguments in their type-sigs gets generalised to
have `IsFilePath a => a` arguments instead, we can't reach the goal of
"Phase 2".

But I suspect that I didn't fully understand how your proposed
transition scheme works exactly... so please correct me where I got it


More information about the Libraries mailing list