diff --git a/AvlTree.cabal b/AvlTree.cabal
--- a/AvlTree.cabal
+++ b/AvlTree.cabal
@@ -1,5 +1,5 @@
 Name:               AvlTree
-Version:            2.4
+Version:            3.0
 Cabal-Version:      >= 1.2
 Build-Type:         Simple
 License:            BSD3
@@ -10,16 +10,16 @@
 Stability:          Stable
 Homepage:           http://www.haskell.org/haskellwiki/AvlTree
 Package-Url:
-Synopsis:           Balanced binary trees using AVL algorithm.
+Synopsis:           Balanced binary trees using the AVL algorithm.
 Description:        A comprehensive library and efficient implementation of AVL trees. The raw AVL
-                    API has been designed with efficiency and generality in mind, not elagance. It
-                    contains all the stuff you really don't want to write yourself if you can avoid
-                    it. This library may be useful for rolling your own Sets, Maps, Sequences, Queues
-                    (for example).
+                    API has been designed with efficiency and generality in mind, not elagance or
+                    safety. It contains all the stuff you really don't want to write yourself if you
+                    can avoid it. This library may be useful for rolling your own Sets, Maps, Sequences,
+                    Queues (for example).
 Category:           Data Structures
 Tested-With:        GHC == 6.8.2, GHC == 6.8.1
 Data-Files:
-Extra-Source-Files: AUTHORS, CHANGELOG, Test/Test.hs, include/ghcdefs.h, include/h98defs.h
+Extra-Source-Files: AUTHORS, CHANGELOG, MasterTable.txt, Test/Test.hs, include/ghcdefs.h, include/h98defs.h
 Extra-Tmp-Files:
 Author:             Adrian Hey
 
@@ -37,6 +37,7 @@
                      Data.Tree.AVL.Read,
                      Data.Tree.AVL.Set,
                      Data.Tree.AVL.Size,
+                     Data.Tree.AVL.Height,
                      Data.Tree.AVL.Split,
                      Data.Tree.AVL.Types,
                      Data.Tree.AVL.Write,
@@ -47,12 +48,11 @@
                      Data.Tree.AVL.Internals.HAVL,
                      Data.Tree.AVL.Internals.HJoin,
                      Data.Tree.AVL.Internals.HPush,
-                     Data.Tree.AVL.Internals.HSet,
-                     Data.Tree.AVL.Internals.HeightUtils
+                     Data.Tree.AVL.Internals.HSet
  Extensions:         CPP
  Hs-Source-Dirs:     .
  Build-Tools:
- Ghc-Options:        -O -Wall -split-objs
+ Ghc-Options:        -Wall
  Ghc-Prof-Options:
  Ghc-Shared-Options:
  Hugs-Options:
diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,3 +2,13 @@
 ---
 * Initial Hackage/Cabal release.
   Version set to 2.4 to distinguish from the 2.3 (non-cabal) release on my home page.
+
+3.0
+---
+* Included MasterTable.txt in the distro.
+* Eq and Ord Instances now based on strict structural equality (derived)
+* Exposed height related functions
+
+
+
+
diff --git a/Data/Tree/AVL.hs b/Data/Tree/AVL.hs
--- a/Data/Tree/AVL.hs
+++ b/Data/Tree/AVL.hs
@@ -33,7 +33,6 @@
 -- mySelector :: (key,val) -> COrdering val    Tree elements are (key,val) pairs
 -- @
 --
--- Please read the notes in the "Data.Tree.AVL.Types" module documentation too.
 -----------------------------------------------------------------------------
 module Data.Tree.AVL
 (module Data.Tree.AVL.Types,
@@ -47,6 +46,7 @@
  map2AVL,avl2Map,
 
  module Data.Tree.AVL.Size,
+ module Data.Tree.AVL.Height,
  module Data.Tree.AVL.Read,
  module Data.Tree.AVL.Write,
  module Data.Tree.AVL.Push,
@@ -71,6 +71,7 @@
 
 import Data.Tree.AVL.Types hiding (E,N,P,Z)
 import Data.Tree.AVL.Size
+import Data.Tree.AVL.Height
 import Data.Tree.AVL.Read
 import Data.Tree.AVL.Write
 import Data.Tree.AVL.Push
@@ -116,6 +117,7 @@
 avl2Map :: AVL (key,val) -> BaseMap.Map key val
 avl2Map avl = BaseMap.fromDistinctAscList (asListL avl)
 
+{- Not any more!
 -- | Eq is based on equality of the lists produced by 'asListL'. This definition has been placed here
 -- to avoid introducing cyclic dependency between Types.hs and List.hs
 instance Eq e => Eq (AVL e) where
@@ -125,6 +127,8 @@
 -- to avoid introducing cyclic dependency between Types.hs and List.hs
 instance Ord e => Ord (AVL e) where
  x `compare` y =  asListL x `compare` asListL y
+-}
+
 
 -- | Show is based on showing the list produced by 'asListL'. This definition has been placed here
 -- to avoid introducing cyclic dependency between Types.hs and List.hs
diff --git a/Data/Tree/AVL/Height.hs b/Data/Tree/AVL/Height.hs
new file mode 100644
--- /dev/null
+++ b/Data/Tree/AVL/Height.hs
@@ -0,0 +1,99 @@
+{-# OPTIONS_GHC -fglasgow-exts #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Tree.AVL.Height
+-- Copyright   :  (c) Adrian Hey 2004,2005
+-- License     :  BSD3
+--
+-- Maintainer  :  http://homepages.nildram.co.uk/~ahey/em.png
+-- Stability   :  stable
+-- Portability :  portable
+--
+-- AVL tree height related utilities.
+--
+-- The functions defined here are not exported by the main Data.Tree.AVL module
+-- because they violate the policy for AVL tree equality used elsewhere in this library.
+-- You need to import this module explicitly if you want to use any of these functions.
+-----------------------------------------------------------------------------
+module Data.Tree.AVL.Height
+        (-- * AVL tree height utilities.
+         height,addHeight,compareHeight, -- heightInt,
+        ) where
+
+import Data.Tree.AVL.Types(AVL(..))
+
+#ifdef __GLASGOW_HASKELL__
+import GHC.Base
+#include "ghcdefs.h"
+#else
+#include "h98defs.h"
+#endif
+
+-- {-# INLINE heightInt #-} -- Don't want this
+-- heightInt :: AVL e -> Int
+-- heightInt t = ASINT(addHeight L(0) t)
+
+-- | Determine the height of an AVL tree.
+--
+-- Complexity: O(log n)
+{-# INLINE height #-}
+height :: AVL e -> UINT
+height t = addHeight L(0) t
+
+-- | Adds the height of a tree to the first argument.
+--
+-- Complexity: O(log n)
+addHeight :: UINT -> AVL e -> UINT
+addHeight h  E        = h
+addHeight h (N l _ _) = addHeight INCINT2(h) l
+addHeight h (Z l _ _) = addHeight INCINT1(h) l
+addHeight h (P _ _ r) = addHeight INCINT2(h) r
+
+-- | A fast algorithm for comparing the heights of two trees. This algorithm avoids the need
+-- to compute the heights of both trees and should offer better performance if the trees differ
+-- significantly in height. But if you need the heights anyway it will be quicker to just evaluate
+-- them both and compare the results.
+--
+-- Complexity: O(log n), where n is the size of the smaller of the two trees.
+compareHeight :: AVL a -> AVL b -> Ordering
+compareHeight = ch L(0) where                       -- d = hA-hB
+ ch :: UINT -> AVL a -> AVL b -> Ordering
+ ch d  E           E          = COMPAREUINT d L(0)
+ ch d  E          (N l1 _ _ ) = chA DECINT2(d) l1
+ ch d  E          (Z l1 _ _ ) = chA DECINT1(d) l1
+ ch d  E          (P _  _ r1) = chA DECINT2(d) r1
+ ch d (N l0 _ _ )  E          = chB INCINT2(d) l0
+ ch d (N l0 _ _ ) (N l1 _ _ ) = ch          d  l0 l1
+ ch d (N l0 _ _ ) (Z l1 _ _ ) = ch  INCINT1(d) l0 l1
+ ch d (N l0 _ _ ) (P _  _ r1) = ch          d  l0 r1
+ ch d (Z l0 _ _ )  E          = chB INCINT1(d) l0
+ ch d (Z l0 _ _ ) (N l1 _ _ ) = ch  DECINT1(d) l0 l1
+ ch d (Z l0 _ _ ) (Z l1 _ _ ) = ch          d  l0 l1
+ ch d (Z l0 _ _ ) (P _  _ r1) = ch  DECINT1(d) l0 r1
+ ch d (P _  _ r0)  E          = chB INCINT2(d) r0
+ ch d (P _  _ r0) (N l1 _ _ ) = ch          d  r0 l1
+ ch d (P _  _ r0) (Z l1 _ _ ) = ch  INCINT1(d) r0 l1
+ ch d (P _  _ r0) (P _  _ r1) = ch          d  r0 r1
+ -- Tree A ended first, continue with Tree B until hA-hB<0, or Tree B ends
+ chA d tB = case COMPAREUINT d L(0) of
+            LT ->             LT
+            EQ -> case tB of
+                  E        -> EQ
+                  _        -> LT
+            GT -> case tB of
+                  E        -> GT
+                  N l _ _  -> chA DECINT2(d) l
+                  Z l _ _  -> chA DECINT1(d) l
+                  P _ _ r  -> chA DECINT2(d) r
+ -- Tree B ended first, continue with Tree A until hA-hB>0, or Tree A ends
+ chB d tA = case COMPAREUINT d L(0) of
+            GT ->             GT
+            EQ -> case tA of
+                  E        -> EQ
+                  _        -> GT
+            LT -> case tA of
+                  E        -> LT
+                  N l _ _  -> chB INCINT2(d) l
+                  Z l _ _  -> chB INCINT1(d) l
+                  P _ _ r  -> chB INCINT2(d) r
+
diff --git a/Data/Tree/AVL/Internals/HAVL.hs b/Data/Tree/AVL/Internals/HAVL.hs
--- a/Data/Tree/AVL/Internals/HAVL.hs
+++ b/Data/Tree/AVL/Internals/HAVL.hs
@@ -19,7 +19,7 @@
         ) where
 
 import Data.Tree.AVL.Types(AVL(..))
-import Data.Tree.AVL.Internals.HeightUtils(addHeight)
+import Data.Tree.AVL.Height(addHeight)
 import Data.Tree.AVL.Internals.HJoin(spliceH,joinH)
 import Data.Tree.AVL.Internals.HPush(pushHL,pushHR)
 
diff --git a/Data/Tree/AVL/Internals/HeightUtils.hs b/Data/Tree/AVL/Internals/HeightUtils.hs
deleted file mode 100644
--- a/Data/Tree/AVL/Internals/HeightUtils.hs
+++ /dev/null
@@ -1,98 +0,0 @@
-{-# OPTIONS_GHC -fglasgow-exts #-}
------------------------------------------------------------------------------
--- |
--- Module      :  Data.Tree.AVL.Internals.HeightUtils
--- Copyright   :  (c) Adrian Hey 2004,2005
--- License     :  BSD3
---
--- Maintainer  :  http://homepages.nildram.co.uk/~ahey/em.png
--- Stability   :  stable
--- Portability :  portable
---
--- AVL tree height related utilities.
---
--- The functions defined here are not exported by the main Data.Tree.AVL module
--- because they violate the policy for AVL tree equality used elsewhere in this library.
--- You need to import this module explicitly if you want to use any of these functions.
------------------------------------------------------------------------------
-module Data.Tree.AVL.Internals.HeightUtils
-        (height,addHeight,compareHeight, -- heightInt,
-        ) where
-
-import Data.Tree.AVL.Types(AVL(..))
-
-#ifdef __GLASGOW_HASKELL__
-import GHC.Base
-#include "ghcdefs.h"
-#else
-#include "h98defs.h"
-#endif
-
--- {-# INLINE heightInt #-} -- Don't want this
--- heightInt :: AVL e -> Int
--- heightInt t = ASINT(addHeight L(0) t)
-
--- | Determine the height of an AVL tree.
---
--- Complexity: O(log n)
-{-# INLINE height #-}
-height :: AVL e -> UINT
-height t = addHeight L(0) t
-
--- | Adds the height of a tree to the first argument.
---
--- Complexity: O(log n)
-addHeight :: UINT -> AVL e -> UINT
-addHeight h  E        = h
-addHeight h (N l _ _) = addHeight INCINT2(h) l
-addHeight h (Z l _ _) = addHeight INCINT1(h) l
-addHeight h (P _ _ r) = addHeight INCINT2(h) r
-
--- | A fast algorithm for comparing the heights of two trees. This algorithm avoids the need
--- to compute the heights of both trees and should offer better performance if the trees differ
--- significantly in height. But if you need the heights anyway it will be quicker to just evaluate
--- them both and compare the results.
---
--- Complexity: O(log n), where n is the size of the smaller of the two trees.
-compareHeight :: AVL a -> AVL b -> Ordering
-compareHeight = ch L(0) where                       -- d = hA-hB
- ch :: UINT -> AVL a -> AVL b -> Ordering
- ch d  E           E          = COMPAREUINT d L(0)
- ch d  E          (N l1 _ _ ) = chA DECINT2(d) l1
- ch d  E          (Z l1 _ _ ) = chA DECINT1(d) l1
- ch d  E          (P _  _ r1) = chA DECINT2(d) r1
- ch d (N l0 _ _ )  E          = chB INCINT2(d) l0
- ch d (N l0 _ _ ) (N l1 _ _ ) = ch          d  l0 l1
- ch d (N l0 _ _ ) (Z l1 _ _ ) = ch  INCINT1(d) l0 l1
- ch d (N l0 _ _ ) (P _  _ r1) = ch          d  l0 r1
- ch d (Z l0 _ _ )  E          = chB INCINT1(d) l0
- ch d (Z l0 _ _ ) (N l1 _ _ ) = ch  DECINT1(d) l0 l1
- ch d (Z l0 _ _ ) (Z l1 _ _ ) = ch          d  l0 l1
- ch d (Z l0 _ _ ) (P _  _ r1) = ch  DECINT1(d) l0 r1
- ch d (P _  _ r0)  E          = chB INCINT2(d) r0
- ch d (P _  _ r0) (N l1 _ _ ) = ch          d  r0 l1
- ch d (P _  _ r0) (Z l1 _ _ ) = ch  INCINT1(d) r0 l1
- ch d (P _  _ r0) (P _  _ r1) = ch          d  r0 r1
- -- Tree A ended first, continue with Tree B until hA-hB<0, or Tree B ends
- chA d tB = case COMPAREUINT d L(0) of
-            LT ->             LT
-            EQ -> case tB of
-                  E        -> EQ
-                  _        -> LT
-            GT -> case tB of
-                  E        -> GT
-                  N l _ _  -> chA DECINT2(d) l
-                  Z l _ _  -> chA DECINT1(d) l
-                  P _ _ r  -> chA DECINT2(d) r
- -- Tree B ended first, continue with Tree A until hA-hB>0, or Tree A ends
- chB d tA = case COMPAREUINT d L(0) of
-            GT ->             GT
-            EQ -> case tA of
-                  E        -> EQ
-                  _        -> GT
-            LT -> case tA of
-                  E        -> LT
-                  N l _ _  -> chB INCINT2(d) l
-                  Z l _ _  -> chB INCINT1(d) l
-                  P _ _ r  -> chB INCINT2(d) r
-
diff --git a/Data/Tree/AVL/Join.hs b/Data/Tree/AVL/Join.hs
--- a/Data/Tree/AVL/Join.hs
+++ b/Data/Tree/AVL/Join.hs
@@ -18,7 +18,7 @@
 import Data.Tree.AVL.Size(addSize)
 import Data.Tree.AVL.List(asTreeLenL,toListL)
 import Data.Tree.AVL.Internals.DelUtils(popHLN,popHLZ,popHLP)
-import Data.Tree.AVL.Internals.HeightUtils(height,addHeight)
+import Data.Tree.AVL.Height(height,addHeight)
 import Data.Tree.AVL.Internals.HJoin(joinH',spliceH)
 
 import Data.List(foldl')
diff --git a/Data/Tree/AVL/Set.hs b/Data/Tree/AVL/Set.hs
--- a/Data/Tree/AVL/Set.hs
+++ b/Data/Tree/AVL/Set.hs
@@ -46,7 +46,7 @@
 import Prelude -- so haddock finds the symbols there
 
 import Data.Tree.AVL.Types(AVL(..))
-import Data.Tree.AVL.Internals.HeightUtils(addHeight)
+import Data.Tree.AVL.Height(addHeight)
 import Data.Tree.AVL.Internals.HJoin(spliceH)
 import Data.Tree.AVL.Internals.HSet(unionH,unionMaybeH,
                                     intersectionH,intersectionMaybeH,
diff --git a/Data/Tree/AVL/Size.hs b/Data/Tree/AVL/Size.hs
--- a/Data/Tree/AVL/Size.hs
+++ b/Data/Tree/AVL/Size.hs
@@ -17,7 +17,7 @@
         ) where
 
 import Data.Tree.AVL.Types(AVL(..))
-import Data.Tree.AVL.Internals.HeightUtils(addHeight)
+import Data.Tree.AVL.Height(addHeight)
 
 #ifdef __GLASGOW_HASKELL__
 import GHC.Base
diff --git a/Data/Tree/AVL/Test/AllTests.hs b/Data/Tree/AVL/Test/AllTests.hs
--- a/Data/Tree/AVL/Test/AllTests.hs
+++ b/Data/Tree/AVL/Test/AllTests.hs
@@ -1042,7 +1042,7 @@
                                                    mn = min (ls-1) (2*rs-1)
                                                in isBalanced u  &&
                                                   (asListL u == filter even [0..mn] ++ [mn+1..ls-1]) &&
-                                                  isBalanced u_ && (u_ == l_)
+                                                  isBalanced u_ && (asListL u_ == asListL l_)
                              difference = genDifference compare
 
 -- | Test the genDifferenceMaybe function
@@ -1075,7 +1075,7 @@
                                 mx = max (mn+1) 0
                                 listfil = filter odd [0..mn]
                                 listrem = [mx..ls-1]
-                            in isBalanced u && isBalanced u_ && (u_ == l_) &&
+                            in isBalanced u && isBalanced u_ && (asListL u_ == asListL l_) &&
                                (asListL u == listfil ++ listrem)
 
 -- | Test the genIsSubsetOf function
diff --git a/Data/Tree/AVL/Types.hs b/Data/Tree/AVL/Types.hs
--- a/Data/Tree/AVL/Types.hs
+++ b/Data/Tree/AVL/Types.hs
@@ -82,23 +82,19 @@
 -- where appropriate), or using strict variants of the combinators defined in "Data.COrdering",
 -- or using 'seq' etc. in your own code (in any combining comparisons you define, for example).
 --
--- A note about 'Eq' and 'Ord' class instances.
+-- The Eq and Ord instances.
 --
--- For 'AVL' trees the defined instances of 'Ord' and 'Eq' are based on the lists that are produced using
--- the 'Data.Tree.AVL.List.asListL' function (it could just as well have been 'Data.Tree.AVL.List.asListR',
--- the choice is arbitrary but I can only chose one). This means that two trees which contain the same elements
--- in the same order are equal regardless of detailed tree structure. The same principle has been applied to
--- the instances of 'Read' and 'Show'. Unfortunately, this has the undesirable and non-intuitive effect
--- of making \"equal\" trees potentially distinguishable using some functions (such as height).
--- All such functions have been placed in the Data.Tree.AVL.Internals modules, which are not
--- included in the main "Data.Tree.AVL" wrapper. For all \"normal\" functions (f) exported by "Data.Tree.AVL"
--- it is safe to assume that if a and b are 'AVL' trees then (a == b) implies (f a == f b), provided the same
--- is true for the tree elements.
+-- Begining with version 3.0 these are now derived, and hence are defined in terms of
+-- strict structural equality, rather than observational equivalence. The reason for
+-- this change is that the observational equivalence abstraction was technically breakable
+-- with the exposed API. But since this change, some functions which were previously
+-- considered unsafe have become safe to expose (those that measure tree height).
 --
 data AVL e = E                      -- ^ Empty Tree
            | N (AVL e) e (AVL e)    -- ^ BF=-1 (right height > left height)
            | Z (AVL e) e (AVL e)    -- ^ BF= 0
            | P (AVL e) e (AVL e)    -- ^ BF=+1 (left height > right height)
+           deriving(Eq,Ord)
 
 -- A name for the AVL type constructor, fully qualified
 avlTyConName :: String
diff --git a/Data/Tree/AVL/Zipper.hs b/Data/Tree/AVL/Zipper.hs
--- a/Data/Tree/AVL/Zipper.hs
+++ b/Data/Tree/AVL/Zipper.hs
@@ -111,8 +111,8 @@
 
 import Data.Tree.AVL.Types(AVL(..))
 import Data.Tree.AVL.Size(size,addSize)
+import Data.Tree.AVL.Height(height,addHeight)
 import Data.Tree.AVL.Internals.DelUtils(deletePath,popRN,popRZ,popRP,popLN,popLZ,popLP)
-import Data.Tree.AVL.Internals.HeightUtils(height,addHeight)
 import Data.Tree.AVL.Internals.HJoin(spliceH,joinH)
 import Data.Tree.AVL.Internals.HPush(pushHL,pushHR)
 import Data.Tree.AVL.Internals.BinPath(BinPath(..),genOpenPath,writePath,insertPath,sel,goL,goR)
diff --git a/Data/Tree/AVLX.hs b/Data/Tree/AVLX.hs
--- a/Data/Tree/AVLX.hs
+++ b/Data/Tree/AVLX.hs
@@ -14,7 +14,6 @@
 module Data.Tree.AVLX
 (module Data.Tree.AVL -- The normal user AVL API
 -- + Normally Hidden Modules
-,module Data.Tree.AVL.Internals.HeightUtils
 ,module Data.Tree.AVL.Internals.DelUtils
 ,module Data.Tree.AVL.Internals.HPush
 ,module Data.Tree.AVL.Internals.HSet
@@ -30,7 +29,6 @@
 import Data.Tree.AVL hiding (AVL)
 import Data.Tree.AVL.Types(AVL(..))        -- We want constructors exposed
 
-import Data.Tree.AVL.Internals.HeightUtils
 import Data.Tree.AVL.Internals.DelUtils
 import Data.Tree.AVL.Internals.HPush
 import Data.Tree.AVL.Internals.HSet
diff --git a/MasterTable.txt b/MasterTable.txt
new file mode 100644
--- /dev/null
+++ b/MasterTable.txt
@@ -0,0 +1,26 @@
+Change in Height as a function of change in BF.
+These figures are correct even if rebalancing has occurred.
+Cases marked "--" are impossible.
+
+Figures are given for insertion/deletion from left and
+right sub-trees separately, and a combined figure for
+where it's unknown which sub-tree was modified.
+
+         InsL  InsR   Insert  |  DelL  DelR   Delete
+ E->E      0     0       0    |    0     0       0
+ E->N     --    --      --    |   --    --      --
+ E->Z     +1    +1      +1    |   --    --      --
+ E->P     --    --      --    |   --    --      --
+ N->E     --    --      --    |   --    --      --
+ N->N      0     0       0    |    0     0       0
+ N->Z      0     0       0    |   -1    -1      -1
+ N->P     --    --      --    |    0    --       0
+ Z->E     --    --      --    |   -1    -1      -1
+ Z->N     --    +1      +1    |    0    --       0
+ Z->Z      0     0       0    |    0     0       0
+ Z->P     +1    --      +1    |   --     0       0
+ P->E     --    --      --    |   --    --      --
+ P->N     --    --      --    |   --     0       0
+ P->Z      0     0       0    |   -1    -1      -1
+ P->P      0     0       0    |    0     0       0
+
