There's
newCString :: String -> IO CString
peekCString :: CString -> IO String
And you need
fromString :: String -> a
show :: a -> String
My lame attempt
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverlappingInstances #-}
module Main where
import Data.String
import Foreign.C.String
import System.IO.Unsafe
instance IsString CString where
fromString = unsafePerformIO . newCString
instance {-# OVERLAPS #-} Show CString where
show = unsafePerformIO . peekCString
mycs :: CString
mycs = "hello CString"
main = putStrLn $ show mycs
It seems to work. But, having never uttered unsafePerformIO
before I wonder what kind of disaster I'm setting up here? Did I leak memory? Is there a safe approach to this convenience?
No. Your show
function, for example, will return different results for the same CString
value at different times. This is because a CString
is really a mutable string under the hood, equivalent to IORef String
. Because when an expression is evaluated and how many times an expression is evaluated are not specified by the Haskell language, an expression show cs
using your instance will have a non-deterministic value, so most Haskell programmers would say this is not a valid use of unsafePerformIO
, and it is (intentionally) not possible to implement Show CString
without using unsafePerformIO
.
This may be technically safe since you never ever change the memory pointed to by the CString
value. Hence, the values are indeed immutable, and the effect of unsafePerformIO
just mimicks a pure value.
However, the above holds only because you never release memory, and simply leak it every time you allocate a new string with newCString
.
As soon as you fix the memory leak using free
, then you lose safety: unsafePerformIO
will read whatever is found at the old memory address. If you are lucky, this will crash the program. If you are unlucky, this will read garbage data into your strings. Good luck in debugging that.
I would strongly recommend against that approach.
TL;DR:
unsafePerformIO
is unsafe, don't use it unless you know what you are doing. CString
should be used as little as possible, and only to interface with foreign languages.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With