OOP

Nick Kallen phantom@earthlink.net
Mon, 10 Nov 1997 15:58:52 -0800


>...lets consider some other methods, such that use to be
>INHERITED. Say "move". Sure we may use
>
>:: Point = {x :: Real, y :: Real}
>:: Circle = {x :: Real, y :: Real, r :: Real}
>
>class Moveable a
> where
>  move :: (Real,Real) a -> a
>
>instance Moveable Point
> where
>  move (dx,dy) point = { point & x = dx + point.x, y = dy + point.y }
>
>instance Moveable Circle
> where
>  move (dx,dy) circle = { circle & x = dx + circle.x, y = dy + circle.y
>}
>
>but you see that the second definition of "move" looks just like the
>first
>modulo the name of the type and the variable.
>Seems silly to me, consider some more complex function.
>The problem is not how to make sure the right function is called,
>but to reuse the functions so that I do not have to rewrite tham
>again and again even if they still look exactly the same.
>


The retyping problem is annoying, but perhaps if we could do:

class Moveable a
where
    move :: (Real,Real) a -> a
    move (dx, dy) p = {p & x = p.x + dx, y = p.y + dy}

The above definition of movable should work with Point, Circle, etc. (I
honestly don't know off hand whether this will work in Clean already (I
don't think it will). Does anyone know?)
    There is a lack of a construct to define a class in terms of required
fields in a record. The above example demonstrates that p in (move (dx, dy)
p) -must- have some field p.x and p.y. I wish there existed a construct such
that one could say:

class Moveable a
where
    a.x | Arith x
    a.y | Arith y
    .
    .

Thus,

:: Point = {x :: Real, y :: Real}

is a candidate for membership in class Moveable. The compiler could look at
the definition of Point and automatically deduce that it is a member of
Moveable; although, this isn't a good idea--the programmer should explicitly
have to declare:

instance Moveable Point

>I still think extensible records ARE usefull.

The above construct (my final definition of Moveable) -would- allow
extensible records, as I think is quite obvious.

:: Circle = {x :: Real, y :: Real, radius :: Real}
instance Moveable Circle

>BTW, I was thinking about simulating extensible records by type clases
>as
>
>Class PointClass a
> where
>  get_x :: a -> Real
>  set_x :: Real a -> a
>  get_y :: a -> Real
>  set_y :: Real a -> a
>
>Class CircleClass a | PointClass
> where
>  get_r :: a -> Real
>  set_r :: Real a -> a
>The problem is that in the current state of clean's type system we are
>unable
>to overload the definition. I mean, if we define
>
>move :: (Real,Real) a -> a | PointClass a
>
>we (AFAIK) may not define other
>
>move :: (Real,Real) a -> a | SquareClass a
>
>regardless of whether "Square | PointClass" or not. :-(

I could be wrong, but wouldn't the following work?:

instance Moveable Point    // The above definition of Moveable
where
    move (dx, dy) = set_x` o set_y`
    where
        set_x` p = set_x p ((get_x p) + dx)
        set_y` p = set_y p ((get_y p) + dy)

This is quite ugly, in my oppinion, but accomplishes what you're trying to
do. Amusingly, you accomplish (albeit by a very ugly method) my request for
requiring certain fields in a record: your get_x function requires that
there's some x object in whatever datastructure you're using.

>P.S.: Take my posts easy, I have no background in type theory or
>whatever.
>      I'm just throwing on you my silly thoughts.

Likewise here. I'm relatively new to functional programming (and have been
programming in general for far fewer years than anyone else on this list,
I'm sure).