views:

614

answers:

4

Should an API provide Rect::contains(Point) or Point::is_inside(Rect) or both? or Math::contains(Point, Rect) cause it's symmetric?

The same Q goes for LineSegment::contains(Point), Rect::fully_contains(Circle) etc.

+7  A: 

Rect::contains(Point) makes most sense as it is a building block. The other is not really necessary as you would expect every specific shape to implement the operation, whereas the Point does not have to know about every possible shape. The same answer goes for LineSegment.

Regarding the relation between Circle and Rect it is more tricky using most object oriented frameworks and does not have any definitive answer. Some other style of object oriented like CLOS do it by using generic functions and methods making it a non question.

kmkaplan
Indeed - IShape::Contains(Point) and class Rect : IShape
James Ogden
The Circle <> Rect issue is probably best solved using a form of multiple dispatch.
Jasper Bekkers
Bekkers, sure but polymorphism isn't my main aim. Just the basic API. And the Math::contains(Point, Rect) solution is basically the nonpolymorphic equivalent of multiple dispatch. Ditto for Math::contains(Rect, Circle). Thanks
+1  A: 

Depends entirely on what makes the expression of your program cleaner, more aligned with the problem you're trying to solve. So to some extent, all of the above should be fine in different contexts.

However, generally speaking, I am slightly tilted in the favour of Rect::contains(Point) rather than Point::Is_inside(Rect). That's because I think the Point class, since it would be used by all kinds of classes (like a 'Circle', 'Hexagon' etc.) should be very basic and contain only the minimum interface.

Math::contains(Rect, Point) would be my second choice. I would use this approach, if I wanted to keep my Rectangle class very primitive and not add too much "convenience" functions to it.

An important thing to remember is, don't consider the design of your classes as written in stone. Just go ahead and pick the design that looks best now. Whenever your needs change, you can and you should alter it. This is what is called refactoring.

Frederick
A: 

I'm with Frederick on the Math::contains approach, although the biggest drawback in my opinion is that the developer loses the discoverability of IntelliSense in finding the method. That's one of my beefs with Boost and STL.

An example of where Rect::contains eventually goes wrong is the iPhone SDK's method of drawing strings, which is basically String::drawInRect.

stevex
A: 

It depends on the implementation, but like Federick I would also tend to go for Math::contains(Rect,Point), over Rect::contains(Point). The reason for this is that the latter leads to an object hierarchy which includes the contains member function as a virtual, which gets overridden from class to class. This can have a potentially significant overhead where you are dealing with very large numbers of rectangles and similar primitives.

Shane MacLaughlin