asyncio icon indicating copy to clipboard operation
asyncio copied to clipboard

Avoid using subclassing as an API

Open GoogleCodeExporter opened this issue 10 years ago • 11 comments

There's been some good talk at PyCon about the danger of using subclassing as 
an API style, and recommending composition of objects instead.  We should 
review all our APIs to see if we're in danger of falling in this trap.  It is 
one of the reasons asyncore is such a disaster.

Original issue reported on code.google.com by [email protected] on 21 Mar 2013 at 3:50

GoogleCodeExporter avatar Apr 10 '15 16:04 GoogleCodeExporter

Can you show example of desired changes?

Original comment by [email protected] on 21 Mar 2013 at 3:54

GoogleCodeExporter avatar Apr 10 '15 16:04 GoogleCodeExporter

If I understand correctly tulip.selectors can be good example for composition.
What other classes have to follow this way?

Original comment by [email protected] on 22 Apr 2013 at 7:04

GoogleCodeExporter avatar Apr 10 '15 16:04 GoogleCodeExporter

What modules / classes are we worried about in particular here?

Often, perhaps, duck-typing could be used instead?

X doesn't have to derive from Y, it just has to act like a Y.

Or are you invisioning a different style?

Original comment by [email protected] on 28 Sep 2013 at 2:08

GoogleCodeExporter avatar Apr 10 '15 16:04 GoogleCodeExporter

Thanks for the reminder!  I think there are two areas in Tulip where this 
matters.

(1) The implementation of event loops, selectors and proactors uses a lot of 
subclassing internally.  People will undoubtedly add new implementations of 
their own, for all of these.  They will use the standard Tulip base classes.  
Which makes them brittle in case we change those base classes -- essentially 
most implementation details of those base classes become APIs that we can't 
easily change.

(2) Transports and Protocols.  The same issue may arise here.  For Protocols 
I'm less worried, the base class is sufficiently empty that it doesn't matter 
and most people will want to write new ones from scratch.  But the standard 
Transport implementations have lots of internal base classes too and may have 
the same issue.

There are probably some places in the Tulip implementation where isinstance() 
is used, forcing some amount of subclassing.  We should get rid of these.

Original comment by [email protected] on 28 Sep 2013 at 2:17

GoogleCodeExporter avatar Apr 10 '15 16:04 GoogleCodeExporter

As for (1), in case it helps I left comments in rose's event loop 
implementation here, mentioning what methods I didn't implement because I 
relied on the implementation of BaseEventLoop: 
https://github.com/saghul/rose/blob/master/rose/_events.py#L150 I did rely on 
some internal functions for creating the transports, though.

(2) FWIW, I find the current implementation ok, when I did custom transports 
there was nothing which could be reused because it's very implementation 
specific, so I don't see much room for clashing there.

I can remember of one place where isinstance() is used and could cause trouble: 
when checking if a callback is an instance of TimerHandle. Timers might be 
implemented differently so TimerHandle is implementation specific IMHO.

Original comment by saghul on 28 Sep 2013 at 11:17

GoogleCodeExporter avatar Apr 10 '15 16:04 GoogleCodeExporter

I wonder if I should relent and start using ABCs...

Original comment by [email protected] on 30 Sep 2013 at 8:42

GoogleCodeExporter avatar Apr 10 '15 16:04 GoogleCodeExporter

I think people who use internal APIs (marked with a leading underscore) should 
accept that they are taking risks with compatibility. However, if some base 
classes are useful building blocks, perhaps they can be exposed as a public API 
(such as the various base classes in the io module).

I'm mostly thinking about Transports here. I don't think many people will write 
event loops, so the general impact of subclassing will be much lower here.

Original comment by antoine.pitrou on 30 Sep 2013 at 8:46

GoogleCodeExporter avatar Apr 10 '15 16:04 GoogleCodeExporter

Original comment by [email protected] on 16 Oct 2013 at 4:42

  • Added labels: Priority-Low
  • Removed labels: Priority-Medium

GoogleCodeExporter avatar Apr 10 '15 16:04 GoogleCodeExporter

The PEP 3156 has been accepted and asyncio has been merged into Python 3.4. I 
don't think that it's still possible to change such major design anymore. What 
do you think?

Original comment by [email protected] on 16 Jan 2014 at 12:26

GoogleCodeExporter avatar Apr 10 '15 16:04 GoogleCodeExporter

No, but we should probably clarify which classes are meant to be subclassed by 
user code and which exist purely to be subclassed by the asyncio package itself.

Original comment by [email protected] on 16 Jan 2014 at 12:31

GoogleCodeExporter avatar Apr 10 '15 16:04 GoogleCodeExporter

As a design principle this issue is still important (e.s. see discussion in 
issue 115). We should discourage subclassing *implementation* classes. For 
*interface* classes (like those in transports.py and protocols.py) there is no 
problem.

Original comment by [email protected] on 27 Jan 2014 at 6:01

GoogleCodeExporter avatar Apr 10 '15 16:04 GoogleCodeExporter