[Edu-sig] Quadrays again... cross-training in two langauges
Kirby Urner
kurner at oreillyschool.com
Mon Aug 10 21:58:55 CEST 2015
On Mon, Aug 10, 2015 at 12:02 PM, Mark Engelberg <mark.engelberg at gmail.com>
wrote:
>
>
>> The idea of an interface has migrated to that of a "protocol" which
>> provides a ready namespace for a "record".
>>
>
> A protocol is more than just an "interface by a different name" or an
> "interface+namespace".
>
For those not familiar with Java, it's single inheritance, so we don't have
the happy solution of injecting new functionality by adding more base
classes.
In Java, a class is said to "extend" a base class whereas an interface, a
set of promised methods, is something a class "implements".
Whereas on my extend only one class at a time, said class may implement
many interfaces.
I see Clojure taps that ability too:
http://clojure.github.io/clojure/clojure.core-api.html#clojure.core/extend
>
> To understand the significance of a protocol, you need to first understand
> the "expression problem". The expression problem asks you to consider a
> set of polymorphic functions over multiple datatypes. Without controlling
> or being able to recompile the original source code, can you easily extend
> these functions to a new datatype, and can you easily create a new
> polymorphic function across those datatypes?
>
I like to relate these concepts back to basic math and the different number
types we start with, as concentric subsets: N < Z < Q < R < C.
Then a protocol or interface is "the operations" such as - / + * < > and so
on. What common control panel of operations works across these sets?
Clojure, like Java, is not supportive of operator overloading right? I
can't go like:
(defprotocol VectorOps
(__add__ [this other])
(__sub__ [this other])
(len [this])
(__neg__ [this])
(norm [this]))
... and then use (+ A B) to add two vectors, or (- A) to negate one.
I think the basics of Polymorphism may be communicated without introducing
the wrinkle of not having original source code. Not wanting to change it
might be easier for a math student to understand.
Not having the original source code sounds like a social problem, an
institutional issue, vs. a truly theoretical issue, and that's confusing to
newbies.
The + and - operators make sense in a Group, where - is both negation and
for adding a negative inverse.
Add * and / to the mix and we've got a field.
Lots of datatypes participate in group and field relationships, including
numbers module N, which we may imagine as a specific type of number.
That's how I want to anchor the concept of types in Python: in the
primitive number types, then add string and collections (sequences,
maps...).
Mathematics already has a strong sense of "types" which we want to build
on. With members of C, we no longer define > or <.
>>> complex(1,0) < complex(2, 0)
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: unorderable types: complex() < complex()
>
> Typically, OO languages make it easy to add a new datatype (just implement
> all the methods you want to implement for the new datatype), but hard to
> add a new method to an object whose source code you can't recompile.
>
Even if you don't touch the original class, you're free to subclass it --
that's a very common way of adding functionality to a type. A lot of the
standard library works that way. You're not expected to touch the base
class, just subclass and override / extend.
> Typically, FP languages make it easy to add a new function (just take
> cases on the datatype in the body of the function), but no good way to add
> a new case for a new datatype to a function whose source code you can't
> recompile.
>
> Clojure has *two *clean, elegant solutions to the expression problem:
> protocols and multimethods. Protocols, for example, even let you implement
> your own new, custom "methods" on Java's built-in string datatype, which is
> what makes them far more powerful than interfaces. (Look up
> extend-protocol and extend-type for more info).
>
> Most languages don't have a solution to the expression problem. Some claim
> they have a solution because you can choose what sort of extensbility you
> are likely to need (am I more likely to add new datatypes or new
> functions?), and code accordingly using either an FP or OO approach.
> Python roughly falls into this category, but this is not a true solution to
> the expression problem. A true solution in Python involves writing your
> programs using the OO approach, and then google for "Python monkey
> patching" to look up tricks to inject new methods into classes you don't
> control -- it's possible, but generally frowned upon... not particularly
> good style in Python or a design principle we would want to teach students.
>
Here's an example of injecting methods into an existing class, in the
second case using a decorator for that purpose. Usually though,
subclassing is the way to extend functionality.
Note that there's no storing of methods at the instance level.
class Obj:
def methodA(self):
print("MethodA")
def methodB(self):
print("MethodB")
obj = Obj()
print([meth for meth in dir(obj) if "meth" in meth])
def methodC(self):
print("MethodC")
Obj.methodC = methodC # injecting a method post hoc (not organic!)
obj = Obj()
print([meth for meth in dir(obj) if "meth" in meth])
obj.methodC()
def addmeth(m):
"""Decorator to inject a method"""
def rewrite(Klass):
setattr(Klass, m.__name__, m)
print("Adding", m)
return Klass
return rewrite
@addmeth(methodC)
class Obj:
def methodA(self):
print("MethodA")
def methodB(self):
print("MethodB")
obj = Obj()
print([meth for meth in dir(obj) if "meth" in meth])
obj.methodC()
Kirby
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/edu-sig/attachments/20150810/4017602e/attachment-0001.html>
More information about the Edu-sig
mailing list