I started to more towards a protocol-based implementation, which is
actually not *too* hard to do. Please try the "protocols" branch of my
repo (g...@github.com:anntzer/clojure-py.git).
So a protocol is just a set (or a list) of method names. At the very
beginning of the startup, I populate the clojure.protocols namespace
(actually, a Python module, as there is no support for namespaces yet)
with core protocols and protocolfns. For some reason I decided to
implement each protocol as a class with a custom metaclass that 1/
forbids instantiation (like a Java interface) and 2/ overrides
is{subclass,instance} (so that they have the meaning of extends? /
satisfies?). Perhaps that was an overkill and I'll go back to the old
way of doing it but we'll see.
At that point I am able to define all base types and use them to extend
the relevant protocols using the @protocol.extends(some-protocol) class
decorator. This is more work than expected (and far from finished yet)
though because there is no notion of protocol inheritance (a protocol
cannot inherit from another) so there are a ton of protocols to be
registered. Also, at that point RT is not loaded yet (it requires some
of these types to be defined), but protocolfns are already available in
the clojure.protocols namespace.
Once these base types are defined, I am able to import RT and off we
go...
So the current state is: all the relevant protocols are implemented, but
most are not extended with the relevant classes yet. Only ISeq and
Seqable have been taken care of, and incompletely (basically, only in
the places where that was needed to start a REPL -- not even to pass all
tests).
On Wed, May 23, 2012 at 08:51:54PM -0500, Timothy Baldridge wrote:
> That is correct. Protocols are basically a dict of all the types that
> implements at least one of the ProtocolFns defined in the Protocol.
> extends? basically is just a dict lookup in that case.
>
> satisfies? However is what you are probably looking for. satisfies?
> would loop over all the fns in a Protocol and make sure each and every
> fn is extended for the given type. However, since this is much more
> expensive operation extends? is probably what we'd want to use in most
> cases.
Actually this is not the case for clj-jvm:
Clojure 1.4.0
user=> (defprotocol Foo (foo [this]))
Foo
user=> (extend java.lang.Number Foo {})
nil
user=> (and (extends? Foo java.lang.Number) (satisfies? Foo 1))
true
The only difference I can see is that one applies to a type and the
other to a value. On the other hand the two functions have somewhat
different implementations in clj-jvm so I may have missed something.
>
> To be honest, I don't really care for these semantics, but it's the
> way Clojure works. You can actually extend a protocol without ever
> extending a single one of its fns. I guess that's the difference
> between a dynamic language and a more static one.
Sure, I'll live with that (and that's how issubclass and isinstance
currently work). Should we provide a function that checks for full
implementation though?