[project @ 2002-12-12 13:42:46 by ross]
[haskell-directory.git] / GHC / IOBase.lhs
index 1497ec9..54ec69f 100644 (file)
@@ -17,6 +17,8 @@
 module GHC.IOBase where
 
 import GHC.ST
+import GHC.Arr -- to derive Ix class
+import GHC.Enum -- to derive Enum class
 import GHC.STRef
 import GHC.Base
 import GHC.Num -- To get fromInteger etc, needed because of -fno-implicit-prelude
@@ -55,6 +57,19 @@ Libraries - parts of hslibs/lang.
 --SDM
 -}
 
+{-|
+A value of type @'IO' a@ is a computation which, when performed,
+does some I\/O before returning a value of type @a@.  
+
+There is really only one way to \"perform\" an I\/O action: bind it to
+@Main.main@ in your program.  When your program is run, the I\/O will
+be performed.  It isn't possible to perform I\/O from an arbitrary
+function, unless that function is itself in the 'IO' monad and called
+at some point, directly or indirectly, from @Main.main@.
+
+'IO' is a monad, so 'IO' actions can be combined using either the do-notation
+or the '>>' and '>>=' operations from the 'Monad' class.
+-}
 newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
 
 unIO :: IO a -> (State# RealWorld -> (# State# RealWorld, a #))
@@ -116,9 +131,32 @@ free of side effects and independent of its environment.
 If the I\/O computation wrapped in 'unsafePerformIO'
 performs side effects, then the relative order in which those side
 effects take place (relative to the main I\/O trunk, or other calls to
-'unsafePerformIO') is indeterminate.  
-
-However, it is less well known that
+'unsafePerformIO') is indeterminate.  You have to be careful when 
+writing and compiling modules that use 'unsafePerformIO':
+
+  * Use @{\-\# NOINLINE foo \#-\}@ as a pragma on any function @foo@
+       that calls 'unsafePerformIO'.  If the call is inlined,
+       the I\/O may be performed more than once.
+
+  * Use the compiler flag @-fno-cse@ to prevent common sub-expression
+       elimination being performed on the module, which might combine
+       two side effects that were meant to be separate.  A good example
+       is using multiple global variables (like @test@ in the example below).
+
+  * Make sure that the either you switch off let-floating, or that the 
+       call to 'unsafePerformIO' cannot float outside a lambda.  For example, 
+       if you say:
+       @
+          f x = unsafePerformIO (newIORef [])
+       @
+       you may get only one reference cell shared between all calls to @f@.
+       Better would be
+       @
+          f x = unsafePerformIO (newIORef [x])
+       @
+       because now it can't float outside the lambda.
+
+It is less well known that
 'unsafePerformIO' is not type safe.  For example:
 
 >     test :: IORef [a]
@@ -144,7 +182,7 @@ unsafePerformIO (IO m) = case m realWorld# of (# _, r #)   -> r
 'unsafeInterleaveIO' allows 'IO' computation to be deferred lazily.
 When passed a value of type @IO a@, the 'IO' will only be performed
 when the value of the @a@ is demanded.  This is used to implement lazy
-file reading, see 'IO.hGetContents'.
+file reading, see 'System.IO.hGetContents'.
 -}
 {-# NOINLINE unsafeInterleaveIO #-}
 unsafeInterleaveIO :: IO a -> IO a
@@ -432,15 +470,12 @@ showHandle p h duplex =
 -- |The type of exceptions.  Every kind of system-generated exception
 -- has a constructor in the 'Exception' type, and values of other
 -- types may be injected into 'Exception' by coercing them to
--- 'Dynamic' (see the section on Dynamic Exceptions).
---
--- For backwards compatibility with Haskell 98, 'IOError' is a type synonym
--- for 'Exception'.
+-- 'Dynamic' (see the section on Dynamic Exceptions: "Control.Exception\#DynamicExceptions").
 data Exception
   = ArithException     ArithException
        -- ^Exceptions raised by arithmetic
        -- operations.  (NOTE: GHC currently does not throw
-       -- 'ArithException's).
+       -- 'ArithException's except for 'DivideByZero').
   | ArrayException     ArrayException
        -- ^Exceptions raised by array-related
        -- operations.  (NOTE: GHC currently does not throw
@@ -451,7 +486,7 @@ data Exception
        -- fails.  The 'String' argument contains the
        -- location of the assertion in the source program.
   | AsyncException     AsyncException
-       -- ^Asynchronous exceptions (see section on Asynchronous Exceptions).
+       -- ^Asynchronous exceptions (see section on Asynchronous Exceptions: "Control.Exception\#AsynchronousExceptions").
   | BlockedOnDeadMVar
        -- ^The current thread was executing a call to
        -- 'takeMVar' that could never return, because there are no other
@@ -461,7 +496,7 @@ data Exception
        -- deadlocked.  The 'Deadlock' exception is
        -- raised in the main thread only (see also: "Control.Concurrent").
   | DynException       Dynamic
-       -- ^Dynamically typed exceptions (see section on Dynamic Exceptions).
+       -- ^Dynamically typed exceptions (see section on Dynamic Exceptions: "Control.Exception\#DynamicExceptions").
   | ErrorCall          String
        -- ^The 'ErrorCall' exception is thrown by 'error'.  The 'String'
        -- argument of 'ErrorCall' is the string passed to 'error' when it was
@@ -613,6 +648,7 @@ instance Eq Exception where
   BlockedOnDeadMVar   == BlockedOnDeadMVar   = True
   NonTermination      == NonTermination      = True
   Deadlock            == Deadlock            = True
+  _                   == _                   = False
 
 -- -----------------------------------------------------------------------------
 -- The ExitCode type
@@ -640,35 +676,39 @@ throw exception = raise# exception
 
 -- | A variant of 'throw' that can be used within the 'IO' monad.
 --
--- Although 'ioError' has a type that is an instance of the type of 'throw', the
+-- Although 'throwIO' has a type that is an instance of the type of 'throw', the
 -- two functions are subtly different:
 --
 -- > throw e   `seq` return ()  ===> throw e
--- > ioError e `seq` return ()  ===> return ()
+-- > throwIO e `seq` return ()  ===> return ()
 --
 -- The first example will cause the exception @e@ to be raised,
--- whereas the second one won\'t.  In fact, 'ioError' will only cause
+-- whereas the second one won\'t.  In fact, 'throwIO' will only cause
 -- an exception to be raised when it is used within the 'IO' monad.
--- The 'ioError' variant should be used in preference to 'throw' to
+-- The 'throwIO' variant should be used in preference to 'throw' to
 -- raise an exception within the 'IO' monad because it guarantees
 -- ordering with respect to other 'IO' operations, whereas 'throw'
 -- does not.
-ioError         :: Exception -> IO a 
-ioError err    =  IO $ \s -> throw err s
+throwIO         :: Exception -> IO a 
+throwIO err    =  IO $ \s -> throw err s
 
 ioException    :: IOException -> IO a
 ioException err =  IO $ \s -> throw (IOException err) s
 
+ioError         :: IOError -> IO a 
+ioError                =  ioException
+
 -- ---------------------------------------------------------------------------
 -- IOError type
 
--- A value @IOError@ encode errors occurred in the @IO@ monad.
--- An @IOError@ records a more specific error type, a descriptive
+-- | The Haskell 98 type for exceptions in the @IO@ monad.
+-- In Haskell 98, this is an opaque type.
+type IOError = IOException
+
+-- |Exceptions that occur in the @IO@ monad.
+-- An @IOException@ records a more specific error type, a descriptive
 -- string and maybe the handle that was used when the error was
 -- flagged.
-
-type IOError = Exception
-
 data IOException
  = IOError {
      ioe_handle   :: Maybe Handle,   -- the handle used by the action flagging 
@@ -739,7 +779,7 @@ instance Show IOErrorType where
       DynIOError{}      -> "unknown IO error"
 
 userError       :: String  -> IOError
-userError str  =  IOException (IOError Nothing UserError "" str Nothing)
+userError str  =  IOError Nothing UserError "" str Nothing
 
 -- ---------------------------------------------------------------------------
 -- Showing IOErrors
@@ -759,4 +799,10 @@ instance Show IOException where
       (case fn of
         Nothing -> id
         Just name -> showString "\nFile: " . showString name)
+
+-- -----------------------------------------------------------------------------
+-- IOMode type
+
+data IOMode      =  ReadMode | WriteMode | AppendMode | ReadWriteMode
+                    deriving (Eq, Ord, Ix, Enum, Read, Show)
 \end{code}