<div dir="ltr">The event loop interface in PEP 3156 has an extensibility problem.  It seems likely that it will have a method like listen_udp() by the time it's done, but suppose that doesn't make it into the first official release.  Third-party event loop implementations may want to provide UDP support as an extension, but the most consistent way to provide that extension is by adding new methods on the event loop object, where various extensions risk conflicting with each other or with new methods that become standardized later.<div>

<br></div><div style>The PEP specifies the add_reader family of methods in part so that core protocol implementations can be shared across all EventLoop implementations that support these methods.  However, if those transports are implemented in a common base class (like Twisted's PosixReactorBase), there is no way for third-party transports to take advantage of a similar structure.  I'd like to make it possible for transports to be developed independent of a particular EventLoop implementation in a way that is consistent with the way the core transports work.  (This is a bigger concern for tulip than it is for twisted because twisted can update PosixReactorBase more frequently than the stdlib can change)</div>

<div style><br></div><div style>I propose turning the interface around so that transport creation uses static functions that take the event loop as an argument, with a double-dispatch mechanism to allow the event loop to provide the actual implementation when it can:</div>

<div style><br></div><div style>  def create_connection(protocol_factory, host, port, event_loop=None):</div><div style>    if event_loop is None:</div><div style>      event_loop = get_event_loop()</div><div style>    # Note the use of a fully-qualified name in the registry</div>

<div style>    impl = event_loop.get_implementation('tulip.create_connection')</div><div style>    return impl(protocol_factory, host, port)</div><div style><br></div><div style>New third-party transports could provide fallbacks for event loops that don't have their own implementations:</div>

<div style><br></div><div style>  if impl is None:</div><div style>    # These supports_*() functions are placeholders for a to-be-determined introspection interface.</div><div style>    if supports_fd_interface(event_loop):</div>

<div style>      return posix_udp_implementation(*args)</div><div style>    elif supports_iocp_interface(event_loop):</div><div style>      return iocp_udp_implementation(*args)</div><div style>    else:</div><div style>
      raise Exception("This transport is not supported on this event loop")</div>
<div style><br></div><div style>Or they could plug into the event loop's implementation registry:</div><div style><br></div><div style>  LibUVEventLoop.register_implementation('mymodule.listen_udp', libuv_udp_implementation)</div>

<div style><br></div><div style>This does introduce a little magic (is there any precedent for this kind of multiple-dispatch in the standard library?), but I like the way it keeps the event loop interface from getting too big and monolithic.  Third-party transports can avoid naming conflicts without looking fundamentally different from standard ones, and there's a clean path from doing something that's platform-specific (e.g. with add_reader and friends) to supporting multiple event loops to full standardization.  <br>

</div><div style><br></div><div style>-Ben</div></div>