Lambda the Ultimate

inactiveTopic Designing Reusable Classes (PDF)
started 2/13/2003; 9:43:04 PM - last post 2/18/2003; 10:41:01 AM
Manuel Simoni - Designing Reusable Classes (PDF)  blueArrow
2/13/2003; 9:43:04 PM (reads: 2077, responses: 9)
Designing Reusable Classes (PDF)

Ralph E. Johnson, Brian Foote

A solid write-up of some OOP best practices. First, tackles general terms such as Inversion of Control (you don't call us, we call you) and White-Box vs. Black-Box frameworks (the former requiring implementation knowledge, the latter not.)

Then presents a list of methods for improving OO code, such as Recursion introduction (giving related messages similar names, even if they have different parameters), Eliminate case analysis (if the same ifs and elses repeat throughout your code, you've probably missed an abstraction), Class hierarchies should be deep and narrow and Reduce implicit parameter passing.

None of these points are really new and some may be debatable, but overall the paper is a good guide for those looking for the tao of objects (then again, the tao that can be seen is not the real tao.)

A nice quote is "type" should be thought of as protocol and not as class, but I don't want to get anyone started on that again ;)

(There seems to be a longer HTML version of this document here.)


Posted to OOP by Manuel Simoni on 2/13/03; 9:47:27 PM

Toby Reyelts - Re: Designing Reusable Classes (PDF)  blueArrow
2/15/2003; 10:43:06 AM (reads: 909, responses: 1)
Class hierarchies should be deep and narrow

Is this one of those "debatable" points? It appears that the author argues for deep and narrow class hierarchies, because they indicate reuse - through inheritance. However, I've always favored delegation over inheritance - implementation inheritance tends to a fragile system. In fact, the longer I develop software, the more I focus on stronger and more flexible typing and the less I lean towards reuse through inheritance.

Manuel Simoni - Re: Designing Reusable Classes (PDF)  blueArrow
2/15/2003; 11:29:11 AM (reads: 900, responses: 0)
Yeah it's one of them. (in fact all of them are) I agree with you, and have made the same observations.

On the other hand there are cases when changing just one or two methods in a subclass is sufficient and introducing a new component for that purpose would complicate the code.

With regards to typing, I'd really like "protocol typing", and not "class typing", so in the parameter list of a method I could say this parameter must implement method foo(). I'm sure this exists in some languages (Java interfaces don't do the trick for me - I don't want to specifiy the constraint in the class of the objects, but in the method where I use these objects.)

Matt Hellige - Re: Designing Reusable Classes (PDF)  blueArrow
2/17/2003; 7:41:37 AM (reads: 856, responses: 0)
This most definitely is a debatable point, and you're not alone. In fact, the "conventional wisdom" about what a good OO design feels like has changed quite a bit. This is a case where it's become apparent that the things that initially attracted people to OO aren't actually it's most important or most useful features. There are others.

Toby Reyelts - Re: Designing Reusable Classes (PDF)  blueArrow
2/17/2003; 10:19:04 AM (reads: 804, responses: 0)
> so in the parameter list of a method I could say > this parameter must implement method foo().

Yeah, I've been thinking some about this lately - especially in terms of generics. Named conformance can be arbitrarily restricting and the cause of a proliferation of meaningless types and adapters, while structural conformance can be the cause of accidental conformance. I had pondered a type system where types are named and methods declare which types they accept (as usual), but you can optionally declare whether the types must conform in name in addition to structure.

For example,

constraint T {
  foo(); // A T must have method foo - any return type
}

// Nothing conforms to U, unless it explicitly names U. named constraint U { foo(); }

class A { // Conforms to T (structurally). public Float foo(); }

class B : public T { // Conforms to T (named). public String foo(); }

class C : public U { // Conforms to T (structurally), and U (named) public Int foo(); }

class X { // Accepts A, B, and C public void bar( T t ) { t.foo(); } // Only accepts B public void bar( named T t ) { t.foo(); } // Only accepts C public void bar( U u ) { t.foo(); } }

You can get this sort of affect in C++ with templates - By default, template parameters conform structurally, but you can get named conformance by casting the template parameter to a subtype that you want the template parameter to conform to in name.

I don't think it's necessary to be able to declare constraints in method declarations (ala PolyJ where clauses), as long as you are able to declare constraints in an "inner" scope (ala Java nested interfaces). That's one serious shortcoming of C++ templates as they stand now.

Manuel Simoni - Re: Designing Reusable Classes (PDF)  blueArrow
2/17/2003; 1:55:21 PM (reads: 799, responses: 1)
I thought of:

void someMethod(param has-methods foo(), bar()) {
     ...
}

This should mean that param can be any type as long as it has the methods foo() and bar().

Toby Reyelts - Re: Designing Reusable Classes (PDF)  blueArrow
2/18/2003; 7:22:29 AM (reads: 812, responses: 0)
That is fairly similar to PolyJ's where constraint clauses.

The problem I have with it, is it leads towards duplication and verbosity (typing the constraints foo(), bar(), etc... over and over for each use of that parameter in different methods), and the tendency towards a loss of abstraction - should there really be a new type to describe a parameter that has foo(), bar(), etc... methods - probably.

Manuel Simoni - Re: Designing Reusable Classes (PDF)  blueArrow
2/18/2003; 8:09:27 AM (reads: 749, responses: 0)
Well, I use that object OnceAndOnlyOnce...

Toby Reyelts - Re: Designing Reusable Classes (PDF)  blueArrow
2/18/2003; 8:59:57 AM (reads: 736, responses: 0)
> Well, I use that object OnceAndOnlyOnce...

I think you've re-stated my point for me. "OnceAndOnlyOnce" is all about preventing duplication. Where clauses encourage duplication of constraint information.

Manuel Simoni - Re: Designing Reusable Classes (PDF)  blueArrow
2/18/2003; 10:41:01 AM (reads: 741, responses: 0)
Probably, in a static typing model, but I assumed this as an incremental addition to a dynamic typing model, so in all other methods I'd simply not use any type constraints, knowing that the object supports the correct protocol (which my compiler could also find out, btw)

> Well, I use that object OnceAndOnlyOnce... (I meant initialize instead of use)