Concrete to Abstract Data Type


Identity: CtoADT
Category: Data MultiModule
Classifiers: data abstraction
Internal cross references:
External cross references: Cross references outside this catalogue, e.g. to Fowler's refactorings
Language: This has been described in terms of Haskell, but will apply to any language with concrete data types. Note that the Haskell field labels make this particularly smooth, but it is equally possible to define explicit selector functions for this purpose.

Description: Convert a Haskell concrete data type into an abstract type whose constructors are hidden.

-- The Tree data type ...

data Tree a
  = Leaf a |
    Node a (Tree a) (Tree a)

-- ... and a function using it
















flatten :: Tree a -> [a]

flatten (Leaf x) = [x]
flatten (Node x s t)
  = x : flatten s ++ flatten t
  

module Tree (Tree, leaf, node, isLeaf, 
       isNode, val, left, right) where

data Tree a 
 = Leaf a |
   Node a (Tree a) (Tree a)

isLeaf (Leaf _) = True                   
isLeaf _        = False

isNode (Node _ _ _) = True
isNode _            = False

val (Leaf x) = x
val (Node x _ _) = x

left  (Node _ l _) = l
right (Node _ _ r) = r

leaf = Leaf
node = Node


flatten :: Tree a -> [a]

flatten t
  | isleaf t = [val t] 
  | isNode t 
    = val t : flatten (left t) ++ 
              flatten (right t)
  

General comment:

Concrete data types provide direct representations of many kinds of data, and the pattern matching syntax over data types makes for an intuitive style of programming. The drawback of this is the 'rigidity' which results: the representation of the data is visible to all clients of the type. It is often useful to make the representation abstract, prior to a change or extension of the data type.

Left to right comment:

This is a composite refactoring, built using a series of simpler refactorings, each of which enables the pre-condition of its successor. See cross-references for details.

Right to left comment:

It is likely that this transformation will only be invoked in circumstances where earlier refactorings have substantially simplified the representation of an ADT.

Left to right conditions:

There are no conditions on performing this refactoring.

Right to left conditions:

The concrete representation of an ADT can be made visible simply by exporting the constructors. Conversion to a full pattern-matching form of definition requires definitions to be written in an appropriate form.

Analysis required:

There are no conditions on the conversion of a data type into an ADT, and thus no analysis.