# os-string-compat
[](https://github.com/Anteproperispomenon/os-string-compat/actions/workflows/haskell.yml)
[](https://github.com/Anteproperispomenon/os-string-compat/actions/workflows/haskell_cabal.yml)
## Note on Hackage
I haven't been able to get Stack/Cabal to generate versions of the documentation that
properly link to entities from other packages on Hackage. Unfortunately, this means
that you won't see documentation for functions that are just included directly from
other packages, and you won't see links to their source code. To (partially) get around this,
I ran Haddock while Stack was using an older version of [filepath](https://hackage.haskell.org/package/filepath)
so that there would be more visible definitions. Hopefully this will improve the
documentation.
If you want proper documentation of functions (and types), I recommend just checking out
[os-string](https://hackage.haskell.org/package/os-string), since it shouldn't have
that problem.
This may be because I'm trying to compile the documentation on Windows. I might try
at some point to auto-generate the docs with GitHub Actions... once I understand how
to do that.
## Note on macOS
This package may not work with older versions of GHC on macOS; when testing GHC 8.10.1
on macOS on GitHub Actions, it failed to install GHC. This seens to be because ARM support
for mac wasn't added until GHC 8.10.4 (and improved thereafter). To reflect this, macOS is
tested on the oldest version of GHC that still successfully installs on GitHub.
Currently, the oldest version of GHC that is able to compile this package on macOS is `9.2.8`.
## Intro and Purpose
This is a compatibility layer over [os-string](https://hackage.haskell.org/package/os-string)
and (older versions of) [filepath](https://hackage.haskell.org/package/filepath). Notably,
in versions `1.4.100 <= v < 1.5` of `filepath`, the `newtype` `OsString` was defined in
the `filepath` package itself. However, you *can* import these versions of `filepath`
alongside `os-string`, which *also* defines a `newtype` `OsString`. In fact, in versions
`1.4.200` onwards of `filepath` it *recommends* importing `OsString` via `os-string`
instead of via `filepath`.
The problem is, you can't use functions from `os-string` on `OsString`s from `filepath`.
This may not seem like a problem at first, but `os-string` adds *a lot* of functions for
working directly on `OsString`s.
This isn't a problem if you have a version of `filepath` that's newer than `1.5`, but some
packages *require* that `filepath` be older than `1.5`. If you're writing a package that
depends on such a package, you can't use any of the new functions from `os-string` directly.
Fortunately, in both `os-string` and older versions of `filepath`, `OsString` is ultimately
just a `newtype` over `ShortByteString`[^1], so you can coerce between the two definitions of
`OsString`[^2]. That's what this package does: it exposes new versions of functions from
`os-string` that are just coerced to work on `OsString`/`OsPath` from `1.4.100+`.
Note that this package works for both pre-1.5 versions of `filepath` *and* post-1.5 versions
of `filepath`. On newer versions, it just re-exports the functions[^3] from `os-string`, since
`filepath` 1.5+ depends on `os-string`. Therefore, you can import `os-string-compat` instead
of `os-string` and you can use the functions regardless of which version of `filepath` you
have. If you're writing a library, you may want to depend on `os-string-compat` instead of
`os-string`, since it'll enable you to put more lenient bounds on `filepath`.
## Usage
### Stack
If this package still isn't available on Hackage (i.e. if the link
<https://hackage.haskell.org/package/os-string-compat> doesn't lead to
a valid package), you'll have to import this package by adding it to
your `stack.yaml` file. You'll also have to do this if you want to
use an exact *revision* of the package.
e.g.
```yaml
extra-deps:
- git: https://github.com/Anteproperispomenon/os-string-compat
commit: 3ea425f103d2f14e3f9f7f713eb4291fee5b38a4 # keep this up-to-date
```
If this package **is** available on Hackage, you may still have to add
it to the `extra-deps` field in `stack.yaml`, but you won't have to
give an exact commit. You can just say e.g.
```yaml
extra-deps:
- os-string-compat-1.0.1
```
### Cabal
If this package has been added to Hackage, you should be able
to run `cabal update` and then add `os-string-compat >= 1.0.1`
to the `build-depends` field in your `<package_name>.cabal` file.
If it still isn't available on Hackage, then you'll have to
add it to your `cabal.project` file. I haven't used this feature
myself, but it'll probably be something like this:
```
packages: .
source-repository-package
type: git
location: https://github.com/Anteproperispomenon/os-string-compat
tag: 3ea425f103d2f14e3f9f7f713eb4291fee5b38a4
```
(See [cabal docs](https://cabal.readthedocs.io/en/3.4/cabal-project.html)
for more info)
### Using the Modules
After that, instead of importing `System.OsString` etc, you import `System.OsString.Compat`
etc... That is, you use the same module name, but add `.Compat` to the end. Note that this
package doesn't include compatibility modules for `System.OsString.Data.ByteString.Short` or
`System.OsString.Data.ByteString.Short.Word16`, since you can just import them directly
without needing to worry about compatibility with `filepath`; when they were included
in `filepath`, they were known as "System.Os*Path*.Data.ByteString.Short" etc..., so their
module names won't clash.
## To-Do
Possibly add more versions of GHC to GitHub Actions workflows. Also look into how to
use GitHub Actions to automate building documentation/packages for Hackage. Also,
figure out how to cache dependencies for the Stack workflow.
## Footnotes
[^1]: Which is itself a `newtype` over `ByteArray`.
[^2]: Yes, there is a difference between Windows `OsString` and POSIX `OsString`,
but so long as you coerce from `WindowsString` to `WindowsString` or
`PosixString` to `PosixString`, you should be okay.
[^3]: There are a few functions that have different definitions depending on the
version of `os-string`, or only exist in newer versions of `os-string`.
For the former, such as `length`, this package exports its own version
based on newer versions of `length` from `os-string`. That way, its
behaviour is not dependent on the version of `os-string` used. For the
latter, more obscure functions just aren't exported if the version of
`os-string` isn't new enough, while others (especially functions that
the test suites rely on) are defined here, with their definitions just
copied from newer versions of `os-string`.