# If OsPath is intended to replace FilePath why isn't FilePath deprecated

**URL:** <https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405>\
**Category:** Learn\
**Created:** [September 24, 2024, 12:25pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405 "2024-09-24T12:25:55Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![eldritch-cookie](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/eldritch-cookie/32/4130_2.png) [@eldritch-cookie](https://discourse.haskell.org/u/eldritch-cookie)\
**Post date:** [September 24, 2024, 12:25pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/1 "2024-09-24T12:25:55Z")

</div>

if we look at [filepath documentation](https://hackage.haskell.org/package/filepath-1.5.3.0/docs/System-OsPath.html). this seems to me to say that you almost always should use OsPath over FilePath if the cost is the same.

---

<div class="post-metadata">

**Author:** ![mpilgrem](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mpilgrem/32/2529_2.png) [@mpilgrem](https://discourse.haskell.org/u/mpilgrem)\
**Post date:** [October 1, 2024, 11:05pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/2 "2024-10-01T23:05:16Z")

</div>

As, effectively, `System.IO.FilePath` is just a synonym for `[Data.Char.Char]`, I am not sure if ‘deprecate’ is the correct term. In his associated [blog](https://hasufell.github.io/posts/2022-06-29-fixing-haskell-filepaths.html), and elsewhere, Julian Ospald (@hasufell) has already gone the extra mile to urge people to make the change where it counts and explain the benefits of doing so. I think it is a good question to ask if the Haddock documentation for `FilePath` could helpfully say a little more than it currently does. It currently says:

```haskell
-- | File and directory names are values of type 'String', 
-- whose precise meaning is operating system dependent. Files 
-- can be opened, yielding a handle which can then be used to 
-- operate on the contents of that file.

type FilePath = String

```

(EDIT: This documentation is a direct lift of the text at Section 41.2 of the Haskell 2010 Report.)

If I understand the blog correctly, this would be more accurate:

```haskell
-- | File and directory names can be represented by values of type 
-- 'String'. However, the precise meaning is operating system dependent.
-- (In some cases, this can cause problems and other types have been
-- developed to avoid them; see the @filepath@ package.) Files can be
-- opened, yielding a handle which can then be used to operate on the 
-- contents of that file.

type FilePath = String

```

---

<div class="post-metadata">

**Author:** ![eldritch-cookie](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/eldritch-cookie/32/4130_2.png) [@eldritch-cookie](https://discourse.haskell.org/u/eldritch-cookie)\
**Post date:** [October 2, 2024, 11:26am UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/3 "2024-10-02T11:26:08Z")

</div>

sure the proposed documentation change is good but why aren’t the functions and the datatype deprecated with a warning like `head`?

---

<div class="post-metadata">

**Author:** ![hasufell](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/hasufell/32/1250_2.png) [@hasufell](https://discourse.haskell.org/u/hasufell)\
**Post date:** [October 2, 2024, 12:57pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/4 "2024-10-02T12:57:50Z")

</div>

> [@eldritch-cookie](#):
>
> why aren’t the functions and the datatype deprecated with a warning like `head`?

`head` is not deprecated. Also: FilePath and head are part of the Haskell report.

---

<div class="post-metadata">

**Author:** ![mpilgrem](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mpilgrem/32/2529_2.png) [@mpilgrem](https://discourse.haskell.org/u/mpilgrem)\
**Post date:** [October 2, 2024, 4:28pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/5 "2024-10-02T16:28:48Z")

</div>

There are people here better placed than me to answer your question, but this is mine:

Haskell is used in a variety of contexts. In some, the problems with `[Char]` that Julian’s blog post identifies are mission critical. In others, they can be considered relatively unimportant.

An important context is education. There, at least initially, it can be useful to put certain complexity to one side, in order to reveal other things more plainly.

If you are confident that you will be working in an environment where directories and filepaths will involve only ASCII characters, then the problems that Julian identifies can be put to one side.

---

<div class="post-metadata">

**Author:** ![BurningWitness](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/burningwitness/32/3665_2.png) [@BurningWitness](https://discourse.haskell.org/u/BurningWitness)\
**Post date:** [October 2, 2024, 7:17pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/6 "2024-10-02T19:17:13Z")

</div>

> [@eldritch-cookie](#):
>
> this seems to me to say that you almost always should use `OsPath` over `FilePath` if the cost is the same.

The premise is merely that for every operation that accepts/returns a `FilePath` there exists that same operation that accepts/returns an `OsPath` and there’s a conversion in between. The default implicit conversion is [`encodeFS`](https://hackage.haskell.org/package/os-string-2.0.6/docs/System-OsString-Posix.html#v:encodeFS)/`decodeFS`, so there’s no point reaching for `OsPath` if that’s all you’re going to do anyway.

Also as of right now using `OsPath` is excruciatingly tedious, as none of the system functions are where you expect (gotta fetch them from `unix` and `Win32` packages and combine with CPP), general locale encoding is in `GHC.IO.Encoding` (internal module), and all the data conversions are performed at runtime (unless you use Template Haskell).

So, as with all things GHC, come back in five years, things may be different by then.

---

<div class="post-metadata">

**Author:** ![noinia](https://avatars.discourse-cdn.com/v4/letter/n/cab0a1/32.png) [@noinia](https://discourse.haskell.org/u/noinia)\
**Post date:** [October 2, 2024, 8:11pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/7 "2024-10-02T20:11:56Z")

</div>

> [@BurningWitness](#):
>
> Also as of right now using `OsPath` is excruciatingly tedious, as none of the system functions are where you expect (gotta fetch them from `unix` and `Win32` packages and combine with CPP),

no you don’t, you can simply use [file-io: Basic file IO operations via 'OsPath'](https://hackage.haskell.org/package/file-io)

---

<div class="post-metadata">

**Author:** ![BurningWitness](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/burningwitness/32/3665_2.png) [@BurningWitness](https://discourse.haskell.org/u/BurningWitness)\
**Post date:** [October 2, 2024, 8:18pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/8 "2024-10-02T20:18:26Z")

</div>

Didn’t know that existed and I don’t see `getArgs` there, exciting.

---

<div class="post-metadata">

**Author:** ![noinia](https://avatars.discourse-cdn.com/v4/letter/n/cab0a1/32.png) [@noinia](https://discourse.haskell.org/u/noinia)\
**Post date:** [October 2, 2024, 8:28pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/9 "2024-10-02T20:28:15Z")

</div>

Hmm yes, admittedly, I don’t think there is a getArgs version that can return OsStrings yet. I remember a ticket somewhere about some functions that were still missing for that to work / (which was being worked on). Let me see if I can find a reference somewhere.

edit: see e.g. [Support for ospath/osstring · Issue #491 · pcapriotti/optparse-applicative · GitHub](https://github.com/pcapriotti/optparse-applicative/issues/491) and the references therein.

---

<div class="post-metadata">

**Author:** ![hasufell](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/hasufell/32/1250_2.png) [@hasufell](https://discourse.haskell.org/u/hasufell)\
**Post date:** [October 3, 2024, 8:13am UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/10 "2024-10-03T08:13:58Z")

</div>

> [@noinia](#):
>
> I don’t think there is a getArgs version that can return OsStrings yet

That should be easy:

- [unix/System/Posix/Env/PosixString.hsc at 4f7f16875c5e491722eda32df53a7b5c3094e4f9 · haskell/unix · GitHub](https://github.com/haskell/unix/blob/4f7f16875c5e491722eda32df53a7b5c3094e4f9/System/Posix/Env/PosixString.hsc#L179)
- [win32/System/Win32/WindowsString/Console.hsc at 6b5bc0494e292ac122a99a8e20a8acc4bf2c7455 · haskell/win32 · GitHub](https://github.com/haskell/win32/blob/6b5bc0494e292ac122a99a8e20a8acc4bf2c7455/System/Win32/WindowsString/Console.hsc#L115)

But keep in mind that the windows version behaves slightly different than the base `getArgs` (because it uses actual windows API).

---

<div class="post-metadata">

**Author:** ![eldritch-cookie](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/eldritch-cookie/32/4130_2.png) [@eldritch-cookie](https://discourse.haskell.org/u/eldritch-cookie)\
**Post date:** [October 5, 2024, 2:43pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/11 "2024-10-05T14:43:39Z")

</div>

yeah you are correct about head, it only has a warning,sorry for the mistake, about the report it is 14 years old, when it was made it already had many compromises. Currently i know 0 haskell implementations besides GHC so compatibility is not relevant, if we decide something is bad we gain nothing by keeping it

---

<div class="post-metadata">

**Author:** ![atravers](https://avatars.discourse-cdn.com/v4/letter/a/45deac/32.png) [@atravers](https://discourse.haskell.org/u/atravers)\
**Post date:** [October 5, 2024, 4:56pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/12 "2024-10-05T16:56:30Z")

</div>

> **[MicroHs](https://hackage.haskell.org/package/MicroHs)**
>
> A small compiler for Haskell

…and from the final page of the associated paper:

> [@](#):
>
> I would also like to thank package authors (very few) who use Haskell2010 instead of Haskell with GHC-only extensions.

---

<div class="post-metadata">

**Author:** ![hasufell](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/hasufell/32/1250_2.png) [@hasufell](https://discourse.haskell.org/u/hasufell)\
**Post date:** [October 5, 2024, 4:59pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/13 "2024-10-05T16:59:40Z")

</div>

> [@eldritch-cookie](#):
>
> if we decide something is bad we gain nothing by keeping it

That is for CLC to decide.

And I’ll vote rather strictly against proposals that violate the standard.

So I have conflicting goals as filepath maintainer and CLC member.

I think we can make OsPath the defacto standard outside of base and slowly deprecate String/FilePath support from other core libraries. They are not obliged to support FilePath.

With “slowly” I mean 10+ years down the line.

---

<div class="post-metadata">

**Author:** ![OrenGitHub](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/orengithub/32/4495_2.png) [@OrenGitHub](https://discourse.haskell.org/u/OrenGitHub)\
**Post date:** [October 10, 2024, 4:19am UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/14 "2024-10-10T04:19:41Z")

</div>

FWIW, I use FilePath for documentation purposes.  
That is, a String-ly type standing for a filename.  
In my scenario, this file is never opened / read etc.  
So IMHO, this type has a place.

---

<div class="post-metadata">

**Author:** ![noinia](https://avatars.discourse-cdn.com/v4/letter/n/cab0a1/32.png) [@noinia](https://discourse.haskell.org/u/noinia)\
**Post date:** [October 10, 2024, 4:23pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/15 "2024-10-10T16:23:48Z")

</div>

Can you elaborate on that? Why couldn’t you do that with OsPath/OsString? Or rather: why would FilePath be a better choice there than OsPath/OsString?

---

<div class="post-metadata">

**Author:** ![OrenGitHub](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/orengithub/32/4495_2.png) [@OrenGitHub](https://discourse.haskell.org/u/OrenGitHub)\
**Post date:** [October 10, 2024, 6:16pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/16 "2024-10-10T18:16:41Z")

</div>

From a naming perspective, I feel the Os prefix is out of place in my setting:  
I receive a filename which is a field in a json received by yesod web server.  
The actual file is never opened - the name just gets processed and propagated to several places  
in the output json.

---

<div class="post-metadata">

**Author:** ![noinia](https://avatars.discourse-cdn.com/v4/letter/n/cab0a1/32.png) [@noinia](https://discourse.haskell.org/u/noinia)\
**Post date:** [October 10, 2024, 7:38pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/17 "2024-10-10T19:38:31Z")

</div>

I see. Whether a file gets opened/read/written/etc is irrelevant for this discussion though; the main point is that String is not a good representation for paths. OsPath/OsString represent/store this data in a better way (more compact representation, better support for non-asci characters). I would think that that is relevant also in your scenario. I do agree that ‘FilePath’ may be a nicer name than ‘OsPath’, but ultimately that could just be solved using a type alias (i.e ‘type FilePath = OsPath’ ).

---

<div class="post-metadata">

**Author:** ![hasufell](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/hasufell/32/1250_2.png) [@hasufell](https://discourse.haskell.org/u/hasufell)\
**Post date:** [October 11, 2024, 12:29pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/18 "2024-10-11T12:29:45Z")

</div>

Note that it’s an interesting problem on how to encode `OsPath` for json.

If you binary serialize it prescisely, it can’t be deserialized between platforms (maybe that’s a good thing?).

If you encode it as `FilePath`, you lose the original bytes. There’s no simple answer. You have to understand the use case.

---

<div class="post-metadata">

**Author:** ![BurningWitness](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/burningwitness/32/3665_2.png) [@BurningWitness](https://discourse.haskell.org/u/BurningWitness)\
**Post date:** [October 11, 2024, 1:59pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/19 "2024-10-11T13:59:07Z")

</div>

> [@hasufell](#):
>
> If you binary serialize it prescisely, it can’t be deserialized between platforms (maybe that’s a good thing?).

You’re phrasing it as if manipulating system paths is ancient magic and only GHC maintainers have the access to the tomes describing the blood rituals.

Serialization itself is not a problem here: JSON can represent all UTF-8 code points, the [RFC](https://datatracker.ietf.org/doc/html/rfc8259#section-8.2) merely states that deserialization of surrogate points is implementation-defined. `aeson` chooses convert them to replacement characters, that’s anotherr point where you’d lose the bytes.

It is thus the responsibility of the side that wants to serialize the `OsPath` to ensure that it can properly represent it, whether it be explicitly through a conversion (same as what `FilePath` does), or implicitly by guaranteeing the correct encoding through system setup.

---

<div class="post-metadata">

**Author:** ![hasufell](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/hasufell/32/1250_2.png) [@hasufell](https://discourse.haskell.org/u/hasufell)\
**Post date:** [October 11, 2024, 2:48pm UTC](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405/20 "2024-10-11T14:48:08Z")

</div>

> [@BurningWitness](#):
>
> You’re phrasing it as if manipulating system paths is ancient magic and only GHC maintainers have the access to the tomes describing the blood rituals.

Sorry, I don’t understand what this means. What does anything have to do with GHC here?

The `OsPath` type has a platform CPP ifdef around an inner constructor: So trying to construct `OsString (WindowsString x)` on unix is a compile error.

```hs
newtype WindowsString = WindowsString { getWindowsString :: BS.ShortByteString }

newtype PosixString = PosixString { getPosixString :: BS.ShortByteString }

#if defined(mingw32_HOST_OS) || defined( __MINGW32__ )
type PlatformString = WindowsString
#else
type PlatformString = PosixString
#endif

newtype OsString = OsString { getOsString :: PlatformString }

```

> [@BurningWitness](#):
>
> Serialization itself is not a problem here: JSON can represent all UTF-8 code points, the [RFC](https://datatracker.ietf.org/doc/html/rfc8259#section-8.2) merely states that deserialization of surrogate points is implementation-defined.

Again I’m confused. `PosixString` is not guaranteed to be UTF-8 or any unicode.

> [@BurningWitness](#):
>
> It is thus the responsibility of the side that wants to serialize the `OsPath` to ensure that it can properly represent it, whether it be explicitly through a conversion (same as what `FilePath` does), or implicitly by guaranteeing the correct encoding through system setup.

Yes, the conversion to `FilePath` has to make a choice on how to decode. I don’t know what you mean with “same as what FilePath does”. FilePath doesn’t do any conversion on its own. `base` does at the FFI layer and assumes the filepath encoding matches the system locale.

Not all standard libraries do that. It’s questionable and the main reason the new types exist. You’d be subverting the benefits.

If you don’t go the decode-\>encode-\>decode route and try to send OsPath directly over the wire, you need a strategy to deal with OsPaths that are e.g. sent from unix to windows (there might be valid cases of such).

WindowsString/PosixString are more sound.

Does that make it clearer?

[Next page](https://discourse.haskell.org/t/if-ospath-is-intended-to-replace-filepath-why-isnt-filepath-deprecated/10405.md?page=2)
