Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Automatically converting objects into classes

34 views
Skip to first unread message

Markus Baumeister

unread,
Nov 26, 1997, 3:00:00 AM11/26/97
to

Hello,

I'm currently doing some literature research for one of the border themes
of my Ph.D. thesis: how to automatically convert prototypical objects
into classes and how to classify objects into the most fitting (i.e.
most specific) classes.

I have the impression, that both are no themes in OO literature.
While there is a huge amount of papers on how to insert a new class
into the class lattice and how to reorganize the class hierarchy,
only very few seem to exist on the above mentioned topics:

- In Stein's language 'Hybrid' objects may become classes by 'flipping'
a switch
- Lieberherr describes an algorithm to create a class lattice from
example objects (if one interprets his graphs appropriate)
- A few object/class-migration approaches allow an object to migrate
implicitly into their most-specific classes if the
appropriate migration constraints are specified.
- Information Retrieval creates 'classes' from documents by
clustering, but bases this on multi-valued features instead on
typed attributes and methods
- Terminological knowledge representation is concerned with finding
the most specific class for A-box objects
- Image processing does some 'classification' with everything they
can lay their hand on (Neural Nets, Clustering, Machine Learning...)

Did I miss any OO-based algorithms or papers you know about? (The last
three items of the above list are of course no examples for OO-based
algorithms.) What are fitting keywords to search for? ('Classification'
is no one and "from objects to classes" fails since 'from' and 'to'
are stop words)

BTW, I'm not interested in OOA approaches like 'take the nouns' which
are human-based.

Thanks for your effort
Markus Baumeister


--
Markus Baumeister, http://www-i5.informatik.rwth-aachen.de/mbp/
EMail: baume...@informatik.rwth-aachen.de (AMS, MIME)

Chiyaba Njovu

unread,
Nov 26, 1997, 3:00:00 AM11/26/97
to

> Hello,

I am interested in knowing whether the JDBC drivers for Object-Relational
are now on the market. Would anyone advise if there is already some way of
linking an object-Relational Database such as UNisql through a Java
application?.

Thanks


Chiyaba

Chiyaba Njovu

unread,
Nov 26, 1997, 3:00:00 AM11/26/97
to

Joachim Durchholz

unread,
Nov 29, 1997, 3:00:00 AM11/29/97
to

> I'm currently doing some literature research for one of the border
> themes of my Ph.D. thesis: how to automatically convert prototypical
> objects into classes and how to classify objects into the most fitting
> (i.e. most specific) classes.

I don't know much about it, and I wouldn't think it can be done
automatically. Classifying an object can be difficult enough for a
human, how should a program do that!

> - In Stein's language 'Hybrid' objects may become classes by
> 'flipping' a switch

Doesn't sound very automated to me. I guess the "class" part of the
hybrid object has be be designed by a human (correct me if I'm wrong).

> - Lieberherr describes an algorithm to create a class lattice from
> example objects (if one interprets his graphs appropriate)

This is an outright dangerous approach. Setting up the class lattice is
an analysis task. Analysis means going out and asking the end user what
he wants or rather needs.
Taking a set of sample objects and deriving anything from them is a sure
way to miss common abstractions.

> - A few object/class-migration approaches allow an object to migrate
> implicitly into their most-specific classes if the
> appropriate migration constraints are specified.

Sounds like objects chaning their class at run-time. This isn't a very
common concept (don't ask me why).

> - Information Retrieval creates 'classes' from documents by
> clustering, but bases this on multi-valued features instead on
> typed attributes and methods
> - Terminological knowledge representation is concerned with finding
> the most specific class for A-box objects
> - Image processing does some 'classification' with everything they
> can lay their hand on (Neural Nets, Clustering, Machine Learning...)

These classifications are certainly useful, but they aren't OO classes.
They are just groups of document that happen to share some
characteristics; no behaviour is associated with such class creation
(usually).

> What are fitting keywords to search for? ('Classification'
> is no one and "from objects to classes" fails since 'from' and 'to'
> are stop words)

Maybe "convert" near "class" near "object".

HTH
Regards,
Joachim
--
Please don't send unsolicited ads.

Patrick Doyle

unread,
Nov 30, 1997, 3:00:00 AM11/30/97
to

In article <34809224...@munich.netsurf.de>,

Joachim Durchholz <joachim....@munich.netsurf.de> wrote:
>
>> - A few object/class-migration approaches allow an object to migrate
>> implicitly into their most-specific classes if the
>> appropriate migration constraints are specified.
>
>Sounds like objects chaning their class at run-time. This isn't a very
>common concept (don't ask me why).

I can't recall the language's name, but I know there's one which allows
subclasses to be defined in terms of superclasses with an additional
constraint. For example, Square could be defined as a subclass of
Rectangle with Width=Height. Whenever that's true, the object is
treated as a square; otherwise, as a rectangle.

It's an interesting approach, if only I could remember the language's
name. (Can anyone help me here?)

-PD
--
--
Patrick Doyle
doy...@ecf.utoronto.ca

Patrick Logan

unread,
Nov 30, 1997, 3:00:00 AM11/30/97
to

In comp.object Joachim Durchholz <joachim....@munich.netsurf.de> wrote:

: Sounds like objects chaning their class at run-time. This isn't a very


: common concept (don't ask me why).

The primary reason is that it is an obscure technique even in the
languages that support it. There are examples, though. One is the use of
#become: in Smalltalk.

OTOH if you consider the "state" pattern from GoF is a variation of
"changing classes" then it is not uncommon at all to change classes at
runtime.

--
Patrick Logan (H) mailto:plo...@teleport.com
(W) mailto:patr...@gemstone.com
http://www.gemstone.com

There is no such thing as a free variable.

Patrick Logan

unread,
Nov 30, 1997, 3:00:00 AM11/30/97
to

In comp.object Joachim Durchholz <joachim....@munich.netsurf.de> wrote:
: > I'm currently doing some literature research for one of the border

: > themes of my Ph.D. thesis: how to automatically convert prototypical
: > objects into classes and how to classify objects into the most fitting
: > (i.e. most specific) classes.

: I don't know much about it, and I wouldn't think it can be done
: automatically. Classifying an object can be difficult enough for a
: human, how should a program do that!

The Self programming language is prototype based (i.e. no classes, objects
may delegate responsibilities to other objects and change these
relationships at runtime). In the Self implementation, there exist things
very much like classes in order to take advantage of what objects
have in common. This is described in at least one of that project's
papers. (One of the earlier Self papers.) The authors make the analogy of
this implementation to what are explicit classes in other languages. The
implementation, as I recall, creates and removes these class-like things
behind the scenes.

Making good classifications from scratch is difficult for developers.
Finding commonalities in pre-existing objects would not be difficult
because it does not have to make judgements of "goodness" from a design
standpoint.

Dave Harris

unread,
Nov 30, 1997, 3:00:00 AM11/30/97
to

doy...@ecf.toronto.edu (Patrick Doyle) wrote:
> It's an interesting approach, if only I could remember the language's
> name. (Can anyone help me here?)

Cecil and Dylan have predicate objects and classes.

Dave Harris, Swansea, UK | "Weave a circle round him thrice,
bran...@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."

Paul Gover

unread,
Nov 30, 1997, 3:00:00 AM11/30/97
to

Markus Baumeister wrote:

> I'm currently doing some literature research for one of the border themes
> of my Ph.D. thesis: how to automatically convert prototypical objects
> into classes and how to classify objects into the most fitting (i.e.
> most specific) classes.
>

> I have the impression, that both are no themes in OO literature.
> While there is a huge amount of papers on how to insert a new class
> into the class lattice and how to reorganize the class hierarchy,
> only very few seem to exist on the above mentioned topics:

> ...

IMHO there's a similar problem with many OO Design methods: they
concentrate on object relationships (such as one-many aggregates)
and not on finding common classes for the identified objects.

I'm not sure at which point in the development process you are looking.
I suggest this is a design decision, made after the analysis which would
identify and describe your prototypical objects.

I've done a little thinking about this; IMHO the crucial point is to
identify the objects' behaviour. In Smalltalk terms, this would be the
set of methods each object must implement. (In Eiffel terms, I'd guess
it's the contracts specified (pre- and post-conditions, invariants),
though I'm not sure if you can identify them all at this stage in the
analysis. I must _finish_ reading OOSC :-) The next stage is to
identify classes in the existing/bought-in Smalltalk hierarchy (or
whatever
language - I'll stick to Smalltalk, as it's the one I use) which exhibit
behaviour which overlaps with the objects you've identified (in Set
theory
terms, with a non-empty intersection of the behaviour sets).
Then for each new object, if the majority of the behaviour exists in one
class, subclass that for the extra behaviour; if it exists in part in
two
or more classes, construct an aggregate object containing instances of
each class (in Eiffel and other languages supporting multiple
inheritance,
you would use that; I'm not sure what to do with Java's classes and
interfaces).

There are several assumptions in that; one in particular interests me:
the question of identifying classes exhibiting a particular behaviour
in Smalltalk. In Eiffel it's possible to produce a listing of the
pre- and post-conditions, invariants and so forth, which together with
the class descriptions should provide data for a search. In Smalltalk
there's not even a standard "Method selector" browser implemented in
any version I've used (that is, list all the method selectors
implemented
in the the workspace; click on one to see the classes implementing it).
Further, there's no mechanism for defining what a given method selector
should mean (let alone enforcing such a definition). IMHO any Smalltalk
design method should _start_ by building a glossary of method
definitions!

Paul Gover
IBM Warwick Development Group
Mumbling for myself, not IBM.

Tim Ottinger

unread,
Nov 30, 1997, 3:00:00 AM11/30/97
to

> I can't recall the language's name, but I know there's one which allows
> subclasses to be defined in terms of superclasses with an additional
> constraint. For example, Square could be defined as a subclass of
> Rectangle with Width=Height. Whenever that's true, the object is
> treated as a square; otherwise, as a rectangle.

Would those be Cecil's predicate classes? There is some mention of them
in one of our recent Object Magazine Online column. It's an interesting
idea and I'd like to see more examples of how it works in software.

If only we could put a few more hours in each day...

--
tim
+------------------+---------------------+------------------+
| Tim Ottinger | 1810 Summit Dr |Design Consulting |
| tott...@oma.com | Urbana IL 61801 |Training offered: |
| Object Mentor | Tel: (217) 239-4546 | OOD |
| www.oma.com | Fax: (217) 239-4546 | C++ |
+------------------+---------------------+------------------+
The important thing is to never stop questioning. - A.Einstein

Juergen Schlegelmilch

unread,
Dec 1, 1997, 3:00:00 AM12/1/97
to

On 30 Nov 1997, Patrick Logan <plo...@user1.teleport.com> wrote:
>In comp.object Joachim Durchholz <joachim....@munich.netsurf.de> wrote:
>
>: Sounds like objects chaning their class at run-time. This isn't a very
>: common concept (don't ask me why).
>
>The primary reason is that it is an obscure technique even in the
>languages that support it. There are examples, though. One is the use of
>#become: in Smalltalk.

It's not obscure but not type-safe: suppose you have two classes, e.g.
Person and Student, and two variables p and s referencing the same object
of class Student. If you now send this object the message `graduate' (i.e.
it should cease being a Student), then it will no longer be a Student and
variable s will be ill-typed (refering to an object of the wrong type);
it should be set to NULL. Since you do not know whether there are more
variables referencing this object, you will have to use dynamic type checking
and live with run-time type errors.

There are some proposals to handle this situation, most notably in
role models which were designed to allow run-time type changes.

Juergen Schlegelmilch
--
+-----------------------------------------------------------------------------+
Dipl.-Inf. Juergen Schlegelmilch University of Rostock
email: schl...@Informatik.Uni-Rostock.de Computer Science Department
http://www.informatik.uni-rostock.de/~schlegel Database Research Group
Tel: ++49 381 498 3402 18051 Rostock
Fax: ++49 381 498 3426 Germany
+-----------------------------------------------------------------------------+

Malcolm Colton

unread,
Dec 1, 1997, 3:00:00 AM12/1/97
to

I don't know about the other ORDBMS (UniSQL, Informix, IBM), but you can
certainly connect a Java app to the JBMS ORBDMS using JDBC. We license
our JDBC driver from Web Logic.

- malcolm colton
VP Marketing
Cloudscape, Inc.
http://www.cloudscape.com

Drew Wade

unread,
Dec 1, 1997, 3:00:00 AM12/1/97
to

Chiyaba Njovu wrote:
>
> > Hello,
>
> I am interested in knowing whether the JDBC drivers for Object-Relational
> are now on the market. Would anyone advise if there is already some way of
> linking an object-Relational Database such as UNisql through a Java
> application?.
>
> Thanks
>
> Chiyaba


probably not for unisql...haven't heard from them recently.

do you want a java interface to rdbms? (that's one sense of
object-relational mapping). try javasoft's recently announce java/blend
(hope i remember the name correctly).

do you want to know what vendors of dbms backends support access from
front ends using odbc tools or jdbc directly. the answer is to be found
by looking at each vendor's web site. i suspect many rdbms vendors have
done this...they already had odbc, and jdbc isn't much more.
objectivity/db has it, too.

and if you want to write a java program and have your java objects
automatically managed by the underlying odbms, see the odmg standard
(www.odmg.org). many odbms vendors have now implemented some or all of
this. e.g., see our objectivity for java. this is very different than
jdbc. it allows you to program only in java (no need for another
language, translating java classes to tables, etc) and is much faster
and easier.

regards,
drew
--
Drew Wade mailto:dr...@no.name.spam.com
Objectivity, Inc. mailto:in...@no.name.spam.com
301B E. Evelyn Ave. http://www.objectivity.com
Mountain View, CA 94041-1530 +1(650)254-7113,-7171 fax
Name = objectivity

Nick Leaton

unread,
Dec 2, 1997, 3:00:00 AM12/2/97
to tott...@oma.com

Tim Ottinger wrote:
>
> > I can't recall the language's name, but I know there's one which allows
> > subclasses to be defined in terms of superclasses with an additional
> > constraint. For example, Square could be defined as a subclass of
> > Rectangle with Width=Height. Whenever that's true, the object is
> > treated as a square; otherwise, as a rectangle.
>
> Would those be Cecil's predicate classes? There is some mention of them
> in one of our recent Object Magazine Online column. It's an interesting
> idea and I'd like to see more examples of how it works in software.
>

It works with Eiffel. You just add an invariant into square that the
width = height. However, it isn't a good idea. One, the check is a
runtime check so you do not get the advantage of static type checking.
You have the usual circle/ellipse problems so it is better to introduce
another base class and inherit from that.

--

Nick

Markus Baumeister

unread,
Dec 2, 1997, 3:00:00 AM12/2/97
to

In <EKGuI...@ecf.toronto.edu> doy...@ecf.toronto.edu (Patrick Doyle) writes:
> I can't recall the language's name, but I know there's one which allows
>subclasses to be defined in terms of superclasses with an additional
>constraint. For example, Square could be defined as a subclass of
>Rectangle with Width=Height. Whenever that's true, the object is
>treated as a square; otherwise, as a rectangle.

> It's an interesting approach, if only I could remember the language's


>name. (Can anyone help me here?)

As already has been pointed out by others, these are probably Chamber's
predicate classes. The reference is:

@inproceedings{Chambers93,
author = {Craig Chambers},
title = {Predicate Classes},
booktitle = {European Conference on Object--Oriented Programming (ECOOP)},
year = {1993},
editor = {Nierstrasz, Oscar M.},
publisher = {Springer},
series = {LNCS 707}

Patrick Doyle

unread,
Dec 4, 1997, 3:00:00 AM12/4/97
to

In article <3483EB4E...@calfp.co.uk>,
Nick Leaton <nickle@pauillac> wrote:

>> Patrick Doyle wrote:
>>
>> > I can't recall the language's name, but I know there's one which allows
>> > subclasses to be defined in terms of superclasses with an additional
>> > constraint. For example, Square could be defined as a subclass of
>> > Rectangle with Width=Height. Whenever that's true, the object is
>> > treated as a square; otherwise, as a rectangle.
>
>It works with Eiffel. You just add an invariant into square that the
>width = height. However, it isn't a good idea. One, the check is a
>runtime check so you do not get the advantage of static type checking.
>You have the usual circle/ellipse problems so it is better to introduce
>another base class and inherit from that.

No, this is totally different. What I'm talking about is the ability
to declare a RECTANGLE object, and whenever Width = Height, it's
treated as a SQUARE. This has none of the Circle/Ellipse peoblems;
in fact, that's what it was invented to solve, if I'm not mistaken

Tim Ottinger

unread,
Dec 4, 1997, 3:00:00 AM12/4/97
to

> No, this is totally different. What I'm talking about is the ability
> to declare a RECTANGLE object, and whenever Width = Height, it's
> treated as a SQUARE. This has none of the Circle/Ellipse peoblems;
> in fact, that's what it was invented to solve, if I'm not mistaken

Yeah, it's like having classes assume and shed roles as they go
along, so that types change. I'm not totally up on this, and have
my nervous trepidations on the concept. But that's normal for an
idea you're not used to working with.

The nerviousness happens when you think you're working with
a square for the long haul, and it stops being squarish. I'm
not sure this is a problem, but I also don't know how it avoids
being one.

--
Tim

D. Erway

unread,
Dec 5, 1997, 3:00:00 AM12/5/97
to

>>>>> "pd" == Patrick Doyle <doy...@ecf.toronto.edu> writes:

pd> No, this is totally different. What I'm talking about is the ability
pd> to declare a RECTANGLE object, and whenever Width = Height, it's
pd> treated as a SQUARE. This has none of the Circle/Ellipse peoblems;
pd> in fact, that's what it was invented to solve, if I'm not mistaken

Common Lisp Object System, (CLOS), can do this - dynamically change the type
of an object on the fly.

You can also change the inheritance hierarchy on the fly, should you be able
to imagine a use for such a thing...

Don

Don Erway derway at ndc.com
NDC Systems 626-939-3847
5314 N. Irwindale Ave Fax:939-3870
Irwindale, CA, 91706

- Hey everybody - whenever you get email spam - put the address of the
perpetrators in your .sig, and the email greppers will start spamming
each other:
dns-...@AGIS.NET
n...@AGIS.NET
dom...@CYBERPROMO.COM
webmaster@localhost
abuse@localhost
postmaster@localhost

Patrick Doyle

unread,
Dec 6, 1997, 3:00:00 AM12/6/97
to

In article <348795D6...@oma.com>, Tim Ottinger <tott...@oma.com> wrote:
>
>The nerviousness happens when you think you're working with
>a square for the long haul, and it stops being squarish. I'm
>not sure this is a problem, but I also don't know how it avoids
>being one.

Yes, that's tough. The simplest way is to disallow declaration of
objects of predicate classes; ie. you could declare a RECTANGLE, but
not a SQUARE because it's not guaranteed always to be a SQUARE.

There are more complex schemes which would allow you to declare a SQUARE
and then use only the subset of operations which maintain the object's
SQUAREness.

How to Dylan and Cecil do this?

Matthias Hoelzl (tc)

unread,
Dec 11, 1997, 3:00:00 AM12/11/97
to

doy...@ecf.toronto.edu (Patrick Doyle) writes:

> In article <348795D6...@oma.com>, Tim Ottinger <tott...@oma.com> wrote:
> >
> >The nerviousness happens when you think you're working with
> >a square for the long haul, and it stops being squarish. I'm
> >not sure this is a problem, but I also don't know how it avoids
> >being one.

It doesn't. I consider predicate classes most useful when you want to
classify objects dynamically like empty/nonempty buffer, not to
enforce invariants. This allows you to replace if-statements by
method dispatch, e.g. instead of

method do_something (buf@:buffer) {
if (buf.empty,
{ handle_error },
{ perform_action });
}

(which is similar to declaring a member function `do_something' for
the class `buffer') you can write

predicate empty_buffer isa buffer when buffer.empty;
predicate non_empty_buffer isa buffer when not(buffer.empty);

method do_something (buf@:empty_buffer) {
handle_error;
}

method do_something (buf@: non_empty_buffer) {
perform_action;
}

which is sometimes nicer. However it seems impossible to guarantee
type safety in the general case, and if you use predicate classes for
dynamic downcasting then you get all the problems of, well, dynamic
downcasting, together with a few new problems where the interaction
between predicate classes and static typing is not very clear.

> Yes, that's tough. The simplest way is to disallow declaration of
> objects of predicate classes; ie. you could declare a RECTANGLE, but
> not a SQUARE because it's not guaranteed always to be a SQUARE.

In Cecil you can instantiate predicate objects and violations of the
predicate will be caught at run time. However this is less useful
than it seems to be, see the code below.

> There are more complex schemes which would allow you to declare a SQUARE
> and then use only the subset of operations which maintain the object's
> SQUAREness.
>
> How to Dylan and Cecil do this?

Dylan *does not* have predicate classes, Dylan doesn't even have a
possibility to change the class of an object at run time. CLOS does
have the latter possibility, which I personally find to be more useful
that Cecil's predicate classes, but then again I have much more
experience with CLOS than with Cecil.

I have appended some code in Cecil that illustrate how one possible
solution to a design problem involving circles and ellipses might look
like. However I do not claim that this is a particularly good choice;
the way circles and ellipses are handled might be appropriate if you
want to use a special drawing algorithm for circles, I can't think of
any situation where I would recommend something like
`non_convertible_circle', this is purely for illustrative purposes.

-- A template object is similar to a class in other object oriented
-- languages.
-- Fields are like slots or instance variables.
-- Thus the following declaration defines a (named) object `ellipse'
-- that has two fields: the center and a pair holding the two axes.
-- (I'll explain below why I didn't specify a field for each axis.)
--
template object ellipse;
var field center(@:ellipse):pair[int, int];
var field axes(@: ellipse):pair[int, int];

-- In Cecil field accesses and methods are syntactically the same,
-- so I'll define accessors and setters for the `axes' field that
-- make the components look like two separate fields.
--
method a_1(e@:ellipse):int { e.axes.first }
method a_2(e@:ellipse):int { e.axes.second }
method set_a_1(e@:ellipse, new_a_1:int):void {
let old_a_2 := e.axes.second;
e.axes := pair(new_a_1, old_a_2);
}
method set_a_2(e@:ellipse, new_a_2:int):void {
let old_a_1 := e.axes.first;
e.axes := pair(old_a_1, new_a_2);
}

-- Here you see how unnamed objects are created: simply by the
-- statement "object isa ...".
--
method new_ellipse(c:pair[int, int], a1:int, a2:int):ellipse {
object isa ellipse
{ center := c, axes := pair(a1, a2) };
}

-- `circle' is a predicate object: Any ellipse that has equal axes
-- is considered to be a child of `circle'.
--
predicate circle isa ellipse when ellipse.a_1 = ellipse.a_2;

-- Every circle has a radius. Although `radius' doesn't have its
-- own field it is indistinguishable from a normal field from a
-- client's perspective.
--
method radius(c@:circle):int {
c.a_1;
}

-- Setting the radius of a circle changes both axes of the
-- representation.
--
method set_radius(c@:circle, r@:int):void {
c.axes := pair(r, r);
}

-- A circle is created as an ellipse with equal axes. It is not
-- possible to assign a return type of `circle' to this function,
-- so nothing prevents you from accidentally changing it to
-- return ellipses. Bad.
--
method new_circle(c:pair[int, int], r:int):ellipse {
object isa ellipse
{ center := c, axes := pair(r, r) };
}

-- A `non_convertible_circle' is a circle that cannot be converted
-- to an ellipse.
--
template object non_convertible_circle isa circle;

-- Non convertible circles are created by copying the
-- `non_convertible_circle' object. Cecil ensures that the
-- restriction c.a_1 = c.a_2 is never violated for objects
-- that inherit from the predicate object `circle'. If the axes
-- were specified as two distinct slots, if would be impossible
-- to change the radius of a `non_convertible_circle' because
-- after the first slot is changed the object would no longer fulfill
-- its predicate.
--
method new_nc_circle(c:pair[int, int], r:int):non_convertible_circle {
object isa non_convertible_circle
{ center := c, axes := pair(r, r) }
}

-- To avoid runtime errors I override the setters for the axes.
-- Dubious.
--
method set_a_1(c@:non_convertible_circle, r:int):void {
c.axes := pair(r, r);
}

method set_a_2(c@:non_convertible_circle, r:int):void {
c.axes := pair(r, r);
}

-- Here are some methods that show how dispatching works for
-- predicate objects.
--
method draw(e@:ellipse):void {
print_line("Drawing an ellipse with axes "
|| e.a_1.print_string
|| ", "
|| e.a_2.print_string);
}

method draw(c@:circle):void {
print_line("Drawing a circle with radius "
|| c.radius.print_string);
}

-- And here are some test cases.
--
print_line("Creating an ellipse with axes 1, 2");
let my_ellipse:ellipse := new_ellipse(pair(0,0), 1, 2);
my_ellipse.draw;

print_line("Changing second axis to 1");
my_ellipse.a_2 := 1;
my_ellipse.draw;

print_line("\nCreating a circle with radius 1");
let my_circle := new_circle(pair(0,0), 1); -- dynamically typed
my_circle.draw;

print_line("Changing radius to 2");
my_circle.radius := 2;
my_circle.draw;

print_line("Changing first axis to 3");
my_circle.a_1 := 3;
my_circle.draw; -- `my_circle' is no longer a circle

print_line("\nCreating a non-convertible circle with radius 1");
let my_nc_circle:non_convertible_circle := new_nc_circle(pair(0,0), 1);
my_nc_circle.draw;

print_line("Changing radius to 2");
my_nc_circle.radius := 2;
my_nc_circle.draw;

print_line("Changing first axis to 3");
my_nc_circle.a_1 := 3;
my_nc_circle.draw;

-- Here is an illustration of a problem that can arise:

method fail_circle (c@:circle):void {
print_line("\nTesting fail circle");
c.draw;
c.a_1 := 2*c.a_1; -- Oops, invariant no longer valid.
c.draw;
c.radius.print_string.print_line;
}

let test_circle := new_circle(pair(0,0), 1);
fail_circle(test_circle);

-- End of the code.

And here is the output:

---- Running the program ----
Creating an ellipse with axes 1, 2
Drawing an ellipse with axes 1, 2
Changing second axis to 1
Drawing a circle with radius 1

Creating a circle with radius 1
Drawing a circle with radius 1
Changing radius to 2
Drawing a circle with radius 2
Changing first axis to 3
Drawing an ellipse with axes 3, 2

Creating a non-convertible circle with radius 1
Drawing a circle with radius 1
Changing radius to 2
Drawing a circle with radius 2
Changing first axis to 3
Drawing a circle with radius 3

Testing fail circle
Drawing a circle with radius 1
Drawing an ellipse with axes 2, 1


** Error: message "radius" with 1 arg not understood.
Called as:
radius(<anon/ellipse/: 0x8391a51>)


Although this post is already way too long I cannot resist some
additional notes:

* The "natural" way to write the `ellipse' class would be as

template object ellipse;
var field center(@:ellipse):pair[int, int];
var field a_1(@: ellipse):int;
var field a_2(@: ellipse):int;

but this is not possible because when you try to set the
fields `a_1' and `a_2' for instances of `non_convertible_circle'
you get an error since the invariant "c.a_1 = c.a_2" that
has to be fulfulled for non convertible circles is violated
between the two assignments. So you cannot simply take existing
code and add predicates without changing its definition.

* There is no natural semantics for the `set_a_1' method on
`non_convertible_circles'. Setting both axes is one possibility
that may be completely wrong for some applications.

To sum up, I can see no case where predicate classes would provide a
solution to design problems that could not be solved by other means,
but they allow very concise code sometimes. Perhaps the Cecil team
will some day come up with a better interaction between static typing
and predicate objects.

Matthias

Dave Harris

unread,
Dec 11, 1997, 3:00:00 AM12/11/97
to

t...@gauss.muc.de (Matthias Hoelzl (tc))) wrote:
> It doesn't. I consider predicate classes most useful when you want to
> classify objects dynamically like empty/nonempty buffer, not to
> enforce invariants.

Specifically, all the predicate classes should have the same interface as
the base class. Then if an object gets reclassified, at least its
interface doesn't change. (I believe Cecil's type system will enforce this
rule statically if you want.)


> [...] and if you use predicate classes for dynamic downcasting then


> you get all the problems of, well, dynamic downcasting

Isn't this more about multi-methods then the predicate classes themselves?
And multi-methods provide a better solution to the downcasting problem
than downcasts do.

Matthias Hoelzl (tc)

unread,
Dec 14, 1997, 3:00:00 AM12/14/97
to

sc...@btinternet.com (Dave Harris) writes:

> t...@gauss.muc.de (Matthias Hoelzl (tc))) wrote:

> > It doesn't. I consider predicate classes most useful when you want to
> > classify objects dynamically like empty/nonempty buffer, not to
> > enforce invariants.
>

> Specifically, all the predicate classes should have the same interface as
> the base class. Then if an object gets reclassified, at least its
> interface doesn't change. (I believe Cecil's type system will enforce this

> rule statically if you WANT.)

The current Cecil type checker aborts on the system libraries, so I
cannot check whether not changing interfaces for predicates is the
intended behavior, but by my reading of the spec this is not the case.
(I understand the phrase "Accordingly, it should be possible to
type-check programs using predicate objects, under the assumption that
the particular state of the object does not affect its external
interface." to mean that it's the programmer's responsibility that the
condition on the interface is fulfilled.) However if this condition
is fulfilled then, yes, the program can be statically type checked,
although with predicate objects this isn't as helpful as it sounds.

In my opinion imposing the "no extended interface" rule on predicate
objects would be too severe a restriction:

* You can have extended interfaces for predicate objects and still be
statically type safe: Say, in the circle-ellipse example that I
posted, if you use `radius' only in methods specialized on `circle'
and only before the first assignment to the `circle' object it can
be statically determined that the program is type correct. You can
use radius safely even after assignments if it is known that these
assignments don't change the value of the predicate. However,
since predicates can be arbitrary computations (and since slot
accesses are just function calls and can therefore be overridden)
the compiler cannot, in general, statically check whether the
predicate is still valid after *any* assignment to the object.

* In many cases a predicate object is defined because you want to
highlight the fact that the object is in a special state that
supports new kinds of behavior. E.g., it would be strange to allow
a programmer to define a circle as an ellipse with equal axes, but
not to allow her to define a method `radius' for circles.

* The same thinking that leads a programmer to using `circle.radius'
leads him to using `circle.a1', and to proceed with the implicit
assumption `a1' == `a2' in the definition of a method specialized
on `circle'. While the program does not fail with a "message not
understood" error, there is the danger that the wrong assumption
will lead to wrong results with consequences only much later in the
computation, an error very hard to find (even more so because the
error is dependent on the initial values of the computation and may
therefore not show up in the test cases). Thus you get the main
disadvantage of dynamic typing in a program that is supposedly
statically type correct. Here the "no extended interface" rule
would actually lead to less correct programs.

One possibility to improve the interaction between predicate objects
and static type checking would be to force predicate objects to be
constant by default and to allow updates only within special "unsafe"
blocks, so that the parts of the source code where accidents can
happen stand out clearly. However this would prevent you from using
predicate objects for things like I/O buffers where the state can
change without program intervention. And it would complicate the
semantics of predicate classes even more.

> > [...] and if you use predicate classes for dynamic downcasting then
> > you get all the problems of, well, dynamic downcasting
>
> Isn't this more about multi-methods then the predicate classes themselves?
> And multi-methods provide a better solution to the downcasting problem
> than downcasts do.

I agree that multi-methods are a better solution to the downcasting
problem than downcasts, but they are not what I had in mind here. The
dynamic downcasting (in the sense of "casting a pointer or reference
to a base class to a derived class") I mean is the following case:

predicate pred isa foo when ...

define method bar(obj@:foo) { ... }

define method bar(obj@:pred) {
-- Using methods defined on `pred' is safe here.
...
-- Change obj here.
...
-- Invoking some method defined on `pred' but not on `foo' here may
-- fail with a type error.
-- For methods defined on both `foo' and `pred' the "wrong" instance
-- may be invoked.
}

While you can initially be sure that you have the right type of pointer
(to `pred') this is not true in the whole body of `bar(@pred)'.

Matthias

Rainer Joswig

unread,
Dec 14, 1997, 3:00:00 AM12/14/97
to

In article <87wwhce...@gauss.muc.de>, t...@gauss.muc.de (Matthias Hoelzl
(tc)) wrote:

> > There are more complex schemes which would allow you to declare a SQUARE
> > and then use only the subset of operations which maintain the object's
> > SQUAREness.
> >
> > How to Dylan and Cecil do this?
>
> Dylan *does not* have predicate classes, Dylan doesn't even have a
> possibility to change the class of an object at run time. CLOS does
> have the latter possibility, which I personally find to be more useful
> that Cecil's predicate classes, but then again I have much more
> experience with CLOS than with Cecil.


Description Logics are allowing similar things. Look
for languages like LOOM and Classic. You describe "concepts".
You can compute whether a concept description is subsumed
by another concept description. Individuals are classified
according what is know about them. If you add or retract
information they will be reclassified. Inconsistencies
will be detected (e.g. saying c1 is a circle and
saying the height of c1 is 10 and the width of c1 is 20).
There is a large theory about description logics.

--
http://www.lavielle.com/~joswig/

0 new messages