Commits

Jean-Marie Gaillourdet committed 3918d2b

wrote basic documentation

  • Participants
  • Parent commits 93367c4
  • Branches default

Comments (0)

Files changed (3)

global-variables.cabal

 Name:               global-variables
 Version:            1.0
 
-Synopsis:           Declaratively named, global, and top-level mutable
-                    variables without unsafePerformIO.
+Synopsis:           Namespaced, global, and top-level mutable variables without
+                    unsafePerformIO.
 
-Description:        some desc
+Description:
+
+  'Data.Global' provides a global namespace of 'IORef's, 'MVar's and
+  'TVar's. This namespace may be accessed in pure code. Yet reading
+  and writing to those 'IORef's, 'MVar's and 'TVar's happens still in
+  their respective monads.
+  .
+  'Data.Global' is designed to meet the following use cases:
+    .
+    * Simplify the declaration of top-level mutable variables, by
+      avoiding any pragmas as well as 'unsafePerformIO'.
+    .
+    * Avoid having to pass references explicitly throughout the
+      program in order to let distant parts communicate.
+    .
+    * Enable a communication by convention scheme, where
+      e.g. different libraries may communicate without code
+      dependencies.
+    .
+    * Simplify the \"configuration problem\" - at least for code in the
+      IO monad.
+   .
+   Note, that this library does not encourage sloppy software design
+   by re-introducing all bad effects of global
+   variables. Nevertheless, sometimes global variables are a suitable
+   solution to a problem. In that case "Data.Global" simplifies and
+   extends their handling significantly.
+   .
+   Examples are in the documentation of "Data.Global".
 
 License:            BSD3
 License-file:       LICENSE
 Author:             Jean-Marie Gaillourdet and Patrick Michel
-Maintainer:         Jean-Marie Gaillourdet <jmg@gaillourdet.net>    
+Maintainer:         Jean-Marie Gaillourdet <jmg@gaillourdet.net>
 Copyright:          2011 Jean-Marie Gaillourdet
 Bug-Reports:        http://bitbucket.org/jmg/global-variables/issues
 
 
 -- Extra files to be distributed with the package, such as examples or
 -- a README.
--- Extra-source-files:  
+-- Extra-source-files:
 
 Cabal-version:      >=1.2
 
 --                    , Data.Global.IORef
 --                    , Data.Global.TVar
   Hs-Source-Dirs:   src
-  
+
   Build-depends:      base >= 4
                     , containers >= 0.3 && < 0.5
                     , stm >= 2.1 && < 2.2
-  
+
   Other-modules:    Data.Global.Registry
 
   Ghc-Options:      -Wall -O2
-  
+
 Executable          runtests
   if flag(test)
     Buildable:      True

src/Data/Global.hs

+-- -*- encoding: utf-8; fill-column: 95 -*-
+
+-----------------------------------------------------------------------------------------------
+--
+-- Module        : Data.Global
+-- Creation Date : 2011-09-01
+-- Authors       : Jean-Marie Gaillourdet <jmg@gaillourdet.net>
+-- License       : BSD-style
+-- Portability   : all
+--
+--
+-----------------------------------------------------------------------------------------------
+
+-- | 'Data.Global' provides a global namespace of 'IORef's, 'MVar's and 'TVar's. This namespace
+-- may be accessed in pure code. Yet reading and writing to those 'IORef's, 'MVar's and 'TVar's
+-- happens still in their respective monads.
+--
+-- 'Data.Global' is designed to meet the following use cases:
+--
+--   * Simplify the declaration of top-level mutable variables, by avoiding any pragmas as well
+--     as 'unsafePerformIO'.
+--
+--   * Avoid having to pass references explicitly throughout the program in order to let
+--     distant parts communicate.
+--
+--   * Enable a communication by convention scheme, where e.g. different libraries may
+--     communicate without code dependencies.
+--
+--   * Simplify the "configuration problem" - at least for code in the IO monad.
+--
+--  Note, that this library does not encourage sloppy software design by re-introducing all bad
+--  effects of global variables. Nevertheless, sometimes global variables are a suitable
+--  solution to a problem. In that case 'Data.Global' simplifies and extends their handling
+--  significantly.
 module Data.Global (
-    module Data.Global.Registry
+
+  -- * Introductory Example
+  -- $intro
+
+  -- * The Namespace of Global Variables
+  -- $namespace
+
+  -- * Initialization
+  -- $init
+
+  -- * Reference of Variable Declaration Functions
+    declareIORef
+  , declareMVar
+  , declareTVar
+
 ) where
 
 import Data.Global.Registry
 
 
 
+-- $intro
+--
+-- The most simple usage of 'Data.Global' is as follows:
+--
+-- Let there be an 'IORef'!
+--
+-- >>> let ref = declareIORef \"some-cool-variable\" 17
+--
+-- Use @ref@ like any other 'IORef'.
+--
+-- >>> readIORef ref
+-- 17
+--
+-- You can do the same with 'MVar's and 'TVar's.
 
 
 
+-- $namespace
+
+
+
+-- $init
+-- References / variables returned by any of the @declare...@ functions are initialized
+-- as needed with the value provided to @declare...@. Have a look at this example.
+--
+-- @
+-- someVar1, someVar2 :: IORef Int
+-- someVar1 = declareIORef \"my-global-var\" 0
+-- someVar2 = declareIORef \"my-global-var\" 1
+-- @
+--
+-- @someVar1@ and @someVar2@ are guaranteed to always denote the exact same 'IORef', but it is
+-- unspecified whether the first read access to that 'IORef' returns @0@ or @1@. It can even
+-- have any other initial value if it is accessed from some other part of the program.

src/Data/Global/Registry.hs

+-- -*- encoding: utf-8; fill-column: 95 -*-
+
 {-# LANGUAGE CPP, ScopedTypeVariables #-}
+-----------------------------------------------------------------------------------------------
+-- |
+-- Module        : Data.Global.Registry
+-- Creation Date : 2011-09-01
+-- Authors       : Jean-Marie Gaillourdet <jmg@gaillourdet.net>
+-- License       : BSD-style
+-- Portability   : all
+--
+-- The internal module.
+-----------------------------------------------------------------------------------------------
 module Data.Global.Registry (
+  -- * Public Interface
     declareIORef, declareMVar, declareTVar
 
+  -- * Private Testing Interface
   , lookupOrInsert
   , setupRegistry
 ) where
 
+#if __GLASGOW_HASKELL__ < 702
+import Control.Exception       ( evaluate )
+#endif
 import Control.Concurrent.MVar
 import Control.Concurrent.STM
-import Control.Exception
 import Data.IORef
 import Data.Dynamic
 import Data.Map as M
   where
     err ex got = error $ "Data.Global.Registry: Invariant violation\n"
                        ++ "expected: " ++ show ex ++ "\n"
-                       ++ "got: " ++ show got ++ "\n" 
+                       ++ "got: " ++ show got ++ "\n"
 
 #if __GLASGOW_HASKELL__ >= 702
     typ = typeOf val
     lkup :: Registry -> IO (Registry, ref a)
     lkup reg = case M.lookup (typ, name) reg of
         Just ref -> return (reg, fromDyn ref (err typ (dynTypeRep ref)))
-        Nothing -> 
+        Nothing ->
          do { ref <- new val
             ; return (M.insert (typ, name) (toDyn ref) reg, ref)
             }
     typ = typeOf' val
 
     lkup :: Registry -> IO (Registry, ref a)
-    lkup reg = 
-     do { typIdx <- typeRepKey typ 
+    lkup reg =
+     do { typIdx <- typeRepKey typ
         ; case M.lookup (typIdx, name) reg of
             Just ref -> return (reg, fromDyn ref (err typ (dynTypeRep ref)))
-            Nothing -> 
+            Nothing ->
              do { ref <- new val
                 ; _ <- evaluate $ typeOf' ref
                 ; return (M.insert (typIdx, name) (toDyn ref) reg, ref)
 {-# NOINLINE lookupOrInsertTVar #-}
 
 
-
+-- | @declareIORef name val@ maps a variable name to an 'IORef'. Calling it multiple times with the same
+-- @name@ and type of 'val' will always return the same 'IORef'.
+--
+-- @
+-- someVar :: IORef Int
+-- someVar = declareMVar \"my-global-some-var\" 0
+-- @
+--
+-- Note, there is /no/ need to use 'unsafePerformIO' or to add a @{-\# NOINLINE someVar \#-}@
+-- pragma in order to define top-level 'IORef's.
 declareIORef
     :: Typeable a
-    => String
-    -> a
-    -> (IORef a)
+    => String     -- ^ The identifying name
+    -> a          -- ^ The initial value of the 'IORef', it may or may not be used.
+    -> (IORef a)  -- ^ A unique 'IORef' determined by @(name, typeOf val)@. Whether it refers
+                  -- to the given initial value or not is unspecified.
 declareIORef name val = unsafePerformIO $ lookupOrInsertIORef name val
 {-# NOINLINE declareIORef #-}
 
 
 
+-- | @declareMVar name val@ maps a variable name to an 'MVar'. Calling it multiple times with the same
+-- @name@ and type of 'val' will always return the same 'MVar'.
+--
+-- @
+-- someVar :: MVar Int
+-- someVar = declareMVar \"my-global-some-var\" 0
+-- @
+--
+-- Note, there is /no/ need to use 'unsafePerformIO' or to add a @{-\# NOINLINE someVar \#-}@
+-- pragma in order to define top-level 'MVar's.
 declareMVar
     :: Typeable a
-    => String
-    -> a
-    -> (MVar a)
+    => String    -- ^ The identifying name
+    -> a         -- ^ The initial value of the 'MVar', it may or may not be used.
+    -> (MVar a)  -- ^ A unique 'MVar' determined by @(name, typeOf val)@. Whether it refers to
+                 -- the given initial value or not is unspecified.
 declareMVar name val = unsafePerformIO $ lookupOrInsertMVar name val
 {-# NOINLINE declareMVar #-}
 
 
 
+-- | @declareTVar name val@ maps a variable name to an 'TVar'. Calling it multiple times with the same
+-- @name@ and type of 'val' will always return the same 'TVar'.
+--
+-- @
+-- someVar :: TVar Int
+-- someVar = declareMVar \"my-global-some-var\" 0
+-- @
+--
+-- Note, there is /no/ need to use 'unsafePerformIO' or to add a @{-\# NOINLINE someVar \#-}@
+-- pragma in order to define top-level 'TVar's.
 declareTVar
     :: Typeable a
-    => String
-    -> a
-    -> (TVar a)
+    => String    -- ^ The identifying name
+    -> a         -- ^ The initial value of the 'TVar', it may or may not be used.
+    -> (TVar a)  -- ^ A unique 'TVar' determined by @(name, typeOf val)@. Whether it refers to
+                 -- the given initial value or not is unspecified.
 declareTVar name val = unsafePerformIO $ lookupOrInsertTVar name val
 {-# NOINLINE declareTVar #-}