Guido asked me to move it here. anyway, i might as well state my case
better.
in the formal definitions of object oriented programming, objects
are said to encapsulate state and behavior. behavior is largely dependent
on the type of the object, but the state is important nonetheless.
for example, file objects are stateful: they can be opened for reading-only,
writing-only, both, or be closed altogether. still, they are all instances
of the file type.
since generic functions/multi-dispatch come to help the programmer
by reducing boilerplate early type-checking code and providing a
more capable dispatch mechanism -- we can't overlook the state of the
object.
this early type-checking goes against the spirit of pure duck typing (which
i'm fond of), but is crucial when the code has side effects. in this case,
you can't just start executing the code and "hope it works", as the
resources (i.e., files) involved are modified. in this kind of code, you
want to check everything is alright *instead* of suddenly having
an AttributeError/TypeError somewhere.
here's an example:
@dispatch
def copy(src: file, dst: file):
while True:
buf = src.read(1000)
if not buf: break
dst.write(buf)
suppose now that dst is mistakenly opened for reading.
this means src would have already been modified, while
dst.write is bound to fail. if src is a socket, for instance,
this would be destructive.
so if we already go as far as having multiple dispatch, which imposes
constraints on the arguments a function accepts, we might as well
base it on the type and state of the object, rather than only on it's type.
we could say, for example:
@dispatch
def copy(src: file_for_reading, dst: file_for_writing):
file_for_reading is not a type -- it's a checker. it may be defined as
def file_for_reading(obj: file):
return file.mode == "r" and not file.closed
types, by default, would check using isinstance(), but costume
checkers could check for stateful requirements too.
and a note about performance: this check is required whether
it's done explicitly or by the dispatch mechanism, and since
most functions don't require so many overloads, i don't think
it's an issue.
besides, we can have a different decorator for dispatching
by type or by checkers, i.e., @dispatch vs @stateful_dispatch,
or something. the simple @dispatch would use a dictionary,
while the stateful version would use a loop.
-tomer
---------- Forwarded message ----------
From: tomer filiba