[Haskell-cafe] Haskell's overlooked object system: was OO idioms redux

Ralf Laemmel Ralf.Laemmel at cwi.nl
Wed Oct 13 16:17:06 EDT 2004


John Goerzen wrote:

>One of the best features of OO programming is that of inheritance.
>...
>

Oleg, Keean and me have lying around a draft that adds to this
discussion. We reconstruct OCaml's tutorial in Haskell
The short paper version is online and under consideration for FOOL:
http://homepages.cwi.nl/~ralf/OOHaskell/
This work takes advantage of the HList library.

I'll attach some code related to inheritance.
So Haskell is an OOPL.

Ralf


-------------- next part --------------
{-# OPTIONS -fglasgow-exts #-}
{-# OPTIONS -fallow-undecidable-instances #-}

-- In the following, we refer to the tutorial "Objects in Caml"
-- http://caml.inria.fr/ocaml/htmlman/manual005.html
-- 3.2 Reference to self


module SelfObj where

import CommonMain hiding (HDeleteMany, hDeleteMany, TypeCast,typeCast)
import GhcSyntax
import GhcExperiments
import TypeEqBoolGeneric
import TypeEqGeneric1
import TypeCastGeneric2
import Label2

import Data.STRef
import Data.IORef
import Control.Monad.ST
import Control.Monad.Fix

infixr 9 #
m # field = (m .!. field) 

-- A name space for record labels
data MyNS = MyNS
l_get_x   = firstLabel MyNS "get-x"
l_move    = nextLabel l_get_x "move"
l_field_x = nextLabel l_move "field x"
l_print   = nextLabel l_field_x "print"

{-

Ocaml Tutorial:

3.2 Reference to self

A method or an initializer can send messages to self (that is, the
current object). For that, self must be explicitly bound, here to the
variable s (s could be any identifier, even though we will often
choose the name self.

class printable_point x_init =
   object (s)
     val mutable x = x_init
     method get_x = x
     method move d = x <- x + d
     method print = print_int s#get_x
   end;;
let p = new printable_point 7;;
val p : printable_point = <obj>
 
p#print;;
7- : unit = ()

-}

class_printable_point x_init self
  = do
      x <- newIORef x_init
      return $
	   l_field_x .=. x
       .*. l_get_x   .=. readIORef x
       .*. l_move    .=. (\d -> do{v<-readIORef x; writeIORef x (d + v)})
       .*. l_print   .=. ( (self # l_get_x ) >>= print )
       .*. emptyRecord

testp1 = do
	  print "testp1"
	  -- Note that 'mfix' plays the role of 'new' in the OCaml code...
	  p <- mfix (class_printable_point 7)
	  p # l_get_x >>= print
	  p # l_move $ 2
	  p # l_get_x >>= print
	  p # l_print -- Note, the latter prints the state of the mutated obj!
	  print "OK"

{-

Ocaml Tutorial:

3.7 Inheritance

We illustrate inheritance by defining a class of colored points that
inherits from the class of points. This class has all instance
variables and all methods of class point, plus a new instance variable
c and a new method color.

class colored_point x (c : string) =
   object
     inherit point x
     val c = c
     method color = c
   end;;

let p' = new colored_point 5 "red";;
val p' : colored_point = <obj>
 
p'#get_x, p'#color;;
- : int * string = (5, "red")

-}

-- Inheritance is simple: just adding methods...

l_color  = nextLabel l_print "color"

class_colored_point x_init color self
  = do
      p <- class_printable_point x_init self
      return $ l_color .=. (return color) .*. p

testp2 = do
	  print "testp2"
	  -- Note that 'mfix' plays the role of 'new' in the OCaml code...
	  p  <- mfix (class_printable_point 7)
	  p' <- mfix (class_colored_point 5 "red")
	  do{ x <- p' # l_get_x; c <- p' # l_color; print (x,c) }
	  print "OK"

{- 

Ocaml Tutorial:

3.4 Virtual methods

It is possible to declare a method without actually defining it, using
the keyword virtual. ...

class virtual abstract_point x_init =
   object (self)
     val mutable x = x_init
     method virtual get_x : int
     method get_offset = self#get_x - x_init
     method virtual move : int -> unit
   end;;

class point x_init =
   object
     inherit abstract_point x_init
     method get_x = x
     method move d = x <- x + d
   end;;

-}

l_offset  = nextLabel l_color "offset"

-- Note, compared with printable_point, the we just removed the field l_get_x 
-- That made the class uninstantiatable!
-- No need for any a language extension for virtual, abstract.

class_abstract_printable_point x_init self
  = do
      x <- newIORef x_init
      return $
	   l_field_x .=. x
       .*. l_offset  .=. ((self # l_get_x ) >>= (\v -> return$ v - x_init))
       .*. l_print   .=. ( (self # l_get_x ) >>= print )
       .*. emptyRecord

class_concrete_printable_point x_init self
  = do
      p <- class_abstract_printable_point x_init self -- inherit...
      return $ 
      -- add the missing (pure virtual) methods
           l_get_x   .=. (readIORef (self # l_field_x))
       .*. l_move    .=. (\d -> do{v<-readIORef (self # l_field_x); 
                                      writeIORef (self # l_field_x) (d + v)})
       .*. p

testp3 = do
	  print "testp3"
	  -- Note, if the latter is uncommented; we get the 
          -- desired instantiation error.
	  p  <- mfix (class_concrete_printable_point 7)
	  p # l_get_x >>= print
	  p # l_move $ 2
	  p # l_offset >>= print
	  p # l_get_x >>= print
	  p # l_print
	  print "OK"


More information about the Haskell-Cafe mailing list