tags:

views:

103

answers:

2

Common scenario: I have a library that uses other libraries. For example, a math library (let's call it foo) that uses numpy.

Functions of foo can either:

  • return a numpy object (either pure or an inherited reimplementation)
  • return a list
  • return a foo-implemented object that behaves like numpy (performing delegation)

The three solutions can be also restated as:

  • foo passes through the internally used object, clearly stating that its library dependency is also a API dependency (since it returns objects obeying the interface of the numpy library)
  • foo makes use of a common subset of objects that are part of the basis of the language.
  • foo completely hides what it uses internally. Nothing about the underlying libraries escapes from the foo library to the client code.

We are of course in a pros-cons scenario. Transparent or opaque? strong coupling with the underlying tools or not? I know the drill but I am in the process of having to do this choice, and I want to share opinions before taking a decision. Suggestions, ideas, personal experience are greatly appreciated.

+2  A: 

The main question I would think about is how much of your library would return numpy objects? If its pervasive I would go with directly returning a numpy as your so tied to numpy you might as well make it explicit. Plus it will probably make it easier to use other numpy based libraries. If on the other hand you only have a few methods that would return numpy I would either go with the numpy like object or a list, probably the numpy like object.

Joshua
+1: don't waste time wrapping or hiding anything. Just return the other library's objects.
S.Lott
S.Lott: I don't know. It seems appealing, but what if the other library screws up ? what if you want to change it later on for something better ? what if you want to pickle it, and you don't want to pickle the library's object but your own ? In my experience, I seldom saw libraries returning other libraries'objects. Libraries tend to fully wrap what's below them.
Stefano Borini
If the other library screws up, you exposed it -- you exposed the screw-up -- making debugging *possible*. Most Python libraries are built on other libraries which they simply pass through. Look at how urllib2 depends on tons of other stuff. You cannot hide someone else's "screw-up". It's (a) impossible and (b) just layering problems on problems.
S.Lott
+3  A: 

Since you're talking about return values, that's not really about "internal objects" -- you should just document the interfaces your returned objects will support (it's OK if that's a subset of numpy.array or whatever;-). I recommend against returning a reference to your internal mutable attributes and documenting that mutators work to alter your own object indirectly (and NOT documenting it is not much better) -- that leads to way-too-strong coupling down the road.

If you WERE talking about actual internal objects, I'd recommend the Law of Demeter -- in a simplistic reading, if the client's coding a.b.c.d.e.f(), then something is very wrong ("just one dot" may be sometimes extreme, but, "four are Right Out"). Again, the problem is strong coupling -- making it impossible for you to change your internal implementation in even minor ways without breaking a million clients...!

Alex Martelli
Well, yes. I spoke improperly about internal objects. I was referring to "objects of dependencies".
Stefano Borini