Subject: [Sort of] Proving I'm a Hacker Essay

From: Moshe Zadka <[email-masked]>
Date: Fri, 12 May 2000 09:02:21 +0300 (IDT)

Chen asked me to write a short essay, for the 200-interesting-lines
things, so here goes. (I'm not sure how many lines there are, but I like
the way it turned out. Enjoy!)

Variance in OO -- What is it, and what is it good for?
======================================================

One of the most basic concepts in Object Oriented Programming is that of
inheritance. Unfortunately, that concept is a bit muddled thanks to C++
and Java's implementation of the concept, so first I'll try to clear it
up. Object Oriented Programming means there are various objects,
communicating. An object is data, and code that knows how to act on that
data. An object has a type, which describes what it can do. One type can
be a subtype of another, if it "lives up to" the promises made by another
type. Note that a subtype does not necessarily share code with its super
type  -- what is called "implementation inheritance" is a useful method of
code reuse, which does not concern us here. An example of types is JAva
interfaces: there's no code reuse, only stating "promises": "I promise to
have a method called ``foo'', taking one integer and returning a string".

The most basic utility of types, is that a type can be used where any
super-type is expected. This is called ``polymorphism'', in OO lingo.
Notice how object-oriented definitions do *not* forbid a type to promise
*more* then its super-type. For example, assume B is a subtype of A, and
that C is a type, which has a method called foo, returning A. We can
subtype C (lets call the type D), and define foo to return B. Since B is-a
A, D's foo lives up to the standards of C, so it is alright. Note that it
should be assumed that a type which claims to be a subtype is one until
proved otherwise -- just replace C and D with A and B, respectively, in
the above example to see why. 

Consider a minute what would happen if C has a method called foo,
*accepting* A. Then, on the face of it, D can not claim to accept B --
after all, C promised to accept all A's, and not every A is a B. 
However, if C originally promised that foo accepts B, then there is no
problem with D's foo accepting A -- after all, any B is an A, and so would
be accepted by D. Actually, something about which I have not talked about,
but which should be mentioned, is thrown exceptions. Thrown exceptions
follow the same rules for return values, so nothing more should be said.
In a similar vain, I should have been more honest -- I've talked about
parameters as if they were input -- but this is not always the case: many
languages support "out" parameters -- filling in the data. Furthermore,
there are, in many cases, inout parameters. Out parameters follow the same
rules for return values, of course. Inout parameters are a more
interesting case -- since they follow the rules for both input and output
parameters, it turns that *any* subtype must except *exactly* the same
type.

So, here is the dillema (this is the most acute case, there are others
which are similar): you have a type A, with a method foo which has an
inout paremeter of type A. You subtype A to B, and want to have B's foo
accept only Bs -- but you can't. So what do you do? 

Eiffel (covariance): Subtype away! But if B is used as an A, and foo is
called on an A, generate a run-time type-check that the A passed is a B,
and if not, throw a run-time exception. Note that this means that *any*
method's signature has to include "type-mismatch" as possible exception.

Sather (contravariance): Have B's foo accept As. If the programmer wants,
he can put an explicit check that the A is a B, and throw an exception
afterwards. If the method was declared without any provisions for
type-mismatch exceptions, the programmer is out of luck.

Java, C++ (novariance): These are different foos. If you want to call the
right foo, you must cast the "pointer" yourself. This may result in an
invalid pointer (C++'s dynamic_cast) or simply garbage (C++'s
static_cast). Java hasn't got the unsafe version, but it is identical
otherwise.

Python (adhoc-variance): Simply call the right foo. Since there are no
type declerations, the type-mismatch (if any) is only implicit, for
example, by calling a non-existing method. Python will raise an
appropriate exception itself.

Note that Sather has split from Eiffel because of variance, Java and C++
chose the same because that was Stroustroup's view of OO, and Python chose
that way because it was in the right spirit -- less burden on the
programmer, in return for less run-time safety.

--
Moshe Zadka <[email-masked]>
http://www.oreilly.com/news/prescod_0300.html
http://www.linux.org.il -- we put the penguin in .com

---

From: Omer Zak <[email-masked]>
Date: Fri, 12 May 2000 10:08:27 +0300 (IDT)

> Variance in OO -- What is it, and what is it good for?

My own contribution is to examine practical uses of variance in OO.

1. Sexual reproduction.
   Class C has a method called 'fornicate' which accepts objects of class
   A as an inout argument.
   Class D, which inherits from C, accepts objects of class B (which
   inherits from A) as an inout argument.
   C is a female ape.  A is a male ape.
   D is a female homo sapiens.  B is a male homo sapiens.

   The 'fornicate' method accepts an adult, and returns his son as an
   output.

   Elaboration of pathological conditions is left as an exercise to the
   reader.

2. Assembly of PCs.
   Class C is a PC XT, and it accepts class A (a 8088 microprocessor) as
   an argument.
   Class D is a PC AT (which inherits software compatibility from class C)
   and it accepts class B (a 80286 microprocessor) as an argument.

> method's signature has to include "type-mismatch" as possible exception.

The female would be infertile.  Unless class C happens to be a mare and
class B happens to be a horse.  The returned class is neither A nor B
because it is a mule.

> static_cast). Java hasn't got the unsafe version, but it is identical

80286's don't fit into PC XT's motherboards.  But it is possible to coerce
them (by means of a mini board which has 80286 and glue logic, and plugs
into the 8088 socket). 

> programmer, in return for less run-time safety.

I would gladly accept the burden of type declarations in exchange for more
run-time safety.  This is essentially the same as adding assertions to
code ("I assert that variable i is of type signed16bitint").

                                             --- Omer
WARNING:
By sending me unsolicited commercial/political/religious E-mail message/s,
you irrevocably agree to pay me US$500.- (plus any legal expenses incurred
by my trying to collect the amount due) per unsolicited commercial/ 
political/religious E-mail message - for the service of receiving it.

---

From: Moshe Zadka <[email-masked]>
Date: Fri, 12 May 2000 10:31:52 +0300 (IDT)

On Fri, 12 May 2000, Omer Zak wrote:

> run-time safety. 

Would you gladly accept the burden of changin declerations all through
your code because you chose wrong the first time? If you want to write
bugfree code, a much more fertile direction would be unit testing. You can
go all the way, of course, for extreme programming. Type-systems are not
enough for good error detection, and usually hinder more then help. Beside
the fact that it is hard to choose a really good type systems -- seems
like error detection is at add with optimization hints.

little-belief-in-staticly-typed-languages-since-'95-ly y'rs, Z.
--
Moshe Zadka <[email-masked]>
http://www.oreilly.com/news/prescod_0300.html
http://www.linux.org.il -- we put the penguin in .com

---

From: Omer Zak <[email-masked]>
Date: Fri, 12 May 2000 14:49:24 +0300 (IDT)

On Fri, 12 May 2000, Moshe Zadka wrote:

> your code because you chose wrong the first time?

Yes.  If the names for variables and types were chosen correctly, then an
editor substitute command can take care of those substitutions.  Don't
choose one-character names.  Choose names such that it'll be possible to
write a simple pattern, which matches exactly the occurrences, which you
want to modify. 

> ... If you want to write
> bugfree code, a much more fertile direction would be unit testing.

There are always bugs, which are not caught by unit testing.  Just as
there are bugs, which are not caught by type systems, or bugs, which are
not caught by assertions.  The best approach is to use all tools at your
disposal, and invest effort commensurate with the importance of the
program being bug-free. 

> ... You can

If you want to quickly put together a piece of code, then of course type
systems hinder you by forcing you to add declarations for things, which
your favorite interpreter could figure out by itself.

But I don't see it as any different from having to remember to put the
trailing brace in a while or foreach statement, or to put a
grammatically correct else clause for an if statement.

                                             --- Omer
WARNING:
By sending me unsolicited commercial/political/religious E-mail message/s
(known also as "spam"), you irrevocably agree to pay me US$500.- (plus any
legal expenses incurred by my trying to collect the amount due) per
unsolicited commercial/political/religious E-mail message - for the service
of receiving it.

---

From: Moshe Zadka <[email-masked]>
Date: Fri, 12 May 2000 21:44:47 +0300 (IDT)

> write a simple pattern, which matches exactly the occurrences, which you

Using smart editors is a poor substitute for using flexible languages.

> there are bugs, which are not caught by type systems

But bugs that would be so simple as to be caught by type systems will
usually be caught by good unit testing. There *are* bugs which are subtle
enough to evade those -- but it does seem the bugs found by unit testing
include those usually caught by type systems. Yet I do not see enough
people clamouring (as they should) for languages which support
unit-testing. In fact, the only language with decent support for
unit-testing I've seen is Python (if __name__=="__main__"). Someday, I
intend to port Python's module system to Scheme, and then there will be
good unit-testing for Scheme too.

> not caught by assertions. 

I strongly recommend reading some XP book for a good criticism of
assertions. Bottom line: XP folks are seriously against assertions.

> grammatically correct else clause for an if statement.

It is different: you have to make tough choices, way to early in the
design -- you cannot later change class hierarchies easily. 
I'm of the very strong opinion that type-systems should be designed for
opitmization (and not for error detection, which would lead to radically
different type-systems), and that they be optional.

Kind of a premature-optimization-is-the-root-of-all-evil thing.
The only language that got it right was CL (and I do hope a similar
mechanism be added to Python -- it seems not unlikely for 1.7-1.8). The
only languages that got close were ML and Haskell -- not perfect, since
you have to add declerations to get any kind of sensible error messages.

Also note that I believe that part of Java's mess of a type system was
that the designers did not completely decide to go for an error detection
oriented or optimization oriented. And come on, you can't claim "primitive
types" and "final classes" aren't a huge hack.

---

From: Omer Zak <[email-masked]>
Date: Sat, 13 May 2000 00:52:16 +0300 (IDT)

> Using smart editors is a poor substitute for using flexible languages.

I believe that a good language would let the programmer control where he
wants the flexibility and where he prefers to let the compiler protect him
against silly mistakes.

When writing a complicated program, the programmer's brain can remember at
most 7(+/-)2 facts at a time.  The language should let the programmer
decide which 7(+/-)2 facts he needs to remember at the moment.  A
language, which allows the programmer to declare that a certain variable
is statically typed as unsigned integer - relieves the programmer from
having to remember this tiny fact and devote his brain to facts more
important to the programming problem in question. 

> good unit-testing for Scheme too.

See: 
http://www.c2.com/cgi/wiki?DesignByContractAssertionsVsUnitTestsVsTypes
(Design By Contract Assertionns Vs Unit Tests Vs Types)

The authors say, for example, that the only way to properly test private
parts of a class' code is by means of assertions (which I interpret to
mean also type declarations). Unit tests can't get into the class's
private members.

> design -- you cannot later change class hierarchies easily.

When writing a program, there are always some decisions, which have to be
made early.  And some of them are bound to be expensive to change.  If
it's not class hierarchies, then it may be the basic design pattern
selected for solving the problem, or something else. 

> different type-systems), and that they be optional.

I agree that type systems should be optional - a language should provide
for both static typing and dynamic typing.  Most of a program's variables
would be statically typed.  Dynamic typing would be used where it is
really needed.

> Kind of a premature-optimization-is-the-root-of-all-evil thing.

This time, the resource being optimized is the number of facts that a
programmer's brain has to remember simultaneously.  The optimization of
this resource is always very premature and always essential (when a
programmer is forced to overload his memory, bugs creep in in large
quantities).  This may be the Basic Conflict (TM) in software development,
whose resolution requires all kinds of software development tools in
existence.

                                             --- Omer
WARNING:

---

From: Moshe Zadka <[email-masked]>
Date: Sat, 13 May 2000 07:32:40 +0300 (IDT)

> mean also type declarations). Unit tests can't get into the class's

I once saw a quote (and I'll probably get some word wrong) "C++ assumes
you don't trust anybody. CLOS assume you trust everybody. The result is
that thieves program in C++ and honest people program in CLOS".
IOW, lets have the really good flamewar, about whether there should be
something like private-members. (I never believed so) Hence, this part of
the argument does nothing for me.

> selected for solving the problem, or something else. 

But it's best to have as few of those as possible, no?

anyway-we-reached-the-point-where-more-discussion-seems-pointless-so-i'll-
just-shut-up-and-let-history-prove-me-right-ly y'rs, Z.
--
Moshe Zadka <[email-masked]>
http://www.oreilly.com/news/prescod_0300.html
http://www.linux.org.il -- we put the penguin in .com

---

From: Omer Mussaev <[email-masked]>
Date: Sun, 14 May 2000 09:30:36 +0300

> Using smart editors is a poor substitute for using flexible languages.

which is even worse exuce for bad design...

> > there are bugs, which are not caught by type systems

and there are bugs which can not be caught until they are caught... halting
problem, duh.

> good unit-testing for Scheme too.

???? FMH, man. thank you.

> assertions. Bottom line: XP folks are seriously against assertions.

(describe-book 'XP)

> different type-systems), and that they be optional.

for error detection, partial type system would be very nice. the problem
with virtual inheritance as a partial type system is that virtual inheritance
does not make much sense when you step out of scope of sixe D, for different
values of D. So, while doing OO, you end up with a zilliooon of small classes
and even smaller methods, which makes you furios when you want to get the
point
out of a system. You end up with over-enginnering, and then you damn it and
start
writing OO code in bash and refrentially transparent code in C, just because
you
are actually able to put those languages in instruction cahce area of your
head.

Having said that, using strong type system as a hint system for optimization
_does_ make a lot of sense. Moreover, some types can be made disposable, for
gc benefit, some types can be declared as "types with delayed evaluation", so
that
JIT vm's will eat it happily etc.

> types" and "final classes" aren't a huge hack.

read gmayer's opinions for java.

--
Omer Mussaev    051-308-214   mailto:[email-masked]
systems programmer, Mercury Interactive/RND/Conduct/core

---

From: [email-masked]
Date: Sun, 14 May 2000 11:02:25 +0300

> ???? FMH, man. thank you.

profanity is a poor substitute for an explanation.
do explain what you find faulty with python's module system so we can argue
intellegintly.

--
Chen Shapira	Web Developer and Linux Activist
The algorithm for finding the longest path in a graph is NP-complete.
For you systems people, that means it's *real slow*.

---

From: Omer Mussaev <[email-masked]>
Date: Sun, 14 May 2000 10:05:03 +0300

> do explain what you find faulty with python's module system so we can argue

yeah, you"re right.

I do not object to Python's system, but rather to porting a foreign system to
scheme.

I think that making scheme more complicated than it is is actually a bad idea.
scheme lets you do something close using call/cc and syntax-rules, so I think
that porting a foreign paradygm where we have one already is not such a good
idea.

Correct me if I am wrong, but that's my vision.

file IO and process management is of much higher importance, IMHO.

---

From: [email-masked]
Date: Sun, 14 May 2000 11:52:55 +0300

> that porting a foreign paradygm where we have one already is not such a good

On general principal - you are right.
but IMHO call/cc is not a good substitute to module system, and scheme can
benefit from a good one - such as python's.

we don't really over-ride the existing paradigm - since there isn't really one
yet. we are just overdefining it :-)

I do wonder how moshez is planing to do this - so I'll just wait and see.

> file IO and process management is of much higher importance, IMHO.

I agree. but this fact is irrelevant to the discussion.
being of lower priority doesn't mean that a module system isn't the right
thing.

> ------------------------------------------------------------------------
> Always forgetting those important dates?
> Let the eGroups calendar remind you.
> http://click.egroups.com/1/3936/9/_/_/_/958291790/
> ------------------------------------------------------------------------
> 
> To unsubscribe from this group, send an email to:
> [email-masked]
> 
> 
>

---

From: Moshe Zadka <[email-masked]>
Date: Sun, 14 May 2000 11:57:20 +0300 (IDT)

> (describe-book 'XP)

XP is short for Extreme Programming. Search for it on your favourite
search engine or online bookstore.

> read gmayer's opinions for java.

Where can I get them? Is it on the web?

---

From: Moshe Zadka <[email-masked]>
Date: Sun, 14 May 2000 12:00:59 +0300 (IDT)

> I do not object to Python's system, but rather to porting a foreign system to

Umm...what's Unschemish in having

(import file) a macro which opens into (define file (make-module (eval
....)?

---

From: Omer Mussaev <[email-masked]>
Date: Sun, 14 May 2000 11:05:43 +0300

> Where can I get them? Is it on the web?

search on hackers-il archive for message dated Mon, 8 May 2000 22:05:17
+0300
and named [hackers-il] re: object orientation

> @Backup- Protect and Access your data any time, any where on the net.
> Try @Backup FREE and recieve 300 points from mypoints.com Install now:
> http://click.egroups.com/1/2345/9/_/_/_/958294666/

---

From: Omer Zak <[email-masked]>
Date: Fri, 19 May 2000 16:52:43 +0300 (IDT)

> the argument does nothing for me.

There is also the point (which I forgot to mention previously) that a
properly-designed typing system supports information hiding, which is one
of the cornerstones of the modular programming methodology (the only
software engineering methodology, which has proven track record, and which
always succeeds).

By the way, deep inheritance hierarchies fail precisely because of
improper application of the information hiding principle.  In this case,
the principle should probably be re-phrased as the principle of condensing
in one short section all code, which is affected by a decision.

You see, it is failure to modularize a program, when you have to browse
several files and/or several sections of the same file in order to figure
out one design decision or to modify it.  When you can modify your design
decision in exactly one place and it works, then you have properly hidden
it in your program's design.
                                             --- Omer
   "MS-Word keeps thinking it knows what I'm gonna do next and tries to
   help me.  I've lived with my wife for 27 years and SHE can't do that.
   What makes MS-Word think it can?"             Bill Mullins
WARNING:
By sending me unsolicited commercial/political/religious E-mail message/s
(known also as "spam"), you irrevocably agree to pay me US$500.- (plus any
legal expenses incurred by my trying to collect the amount due) per
unsolicited commercial/political/religious E-mail message - for the service
of receiving it.