This is a continuation of issues raised in the thread about making the core
"last" function behave in a polymorphic manner.

The separation of interfaces from implementation in Java serves several
purposes, but one thing it does is it allows the creation of abstract data
types, i.e., a type that is defined in terms of what it can do, rather than
what it is comprised of or how it is implemented.

Right now, in Clojure, ISeq is an interface, and by extension, it is an
abstract type.  One benefit this has is that we can polymorphically
dispatch, via a protocol, for example, on whether something is an ISeq.  We
can easily create a function that applies to anything to which you can
"first" and "rest", and at the same time, we can leave the function open to
extension by other types.

However, once ISeq is made into a protocol (which has already been done in
ClojureScript and may conceivably be done in the future in Clojure), there
is a problem.  No longer can you dispatch via protocols on whether
something is an ISeq.  In other words, by using a protocol to define ISeq.
we have lost its capabilities to express an abstract data type.  Protocols
provide a way to polymorphically dispatch to various concrete data types
but appear to lose the ability to dispatch based on the abstract data type,
i.e., dispatching on what the object can *do*.

A hypothetical polymorphic last function, proposed in that previous thread,
is a great example of why one would want to do this.  A naive
implementation of a polymorphic last could take the form "(cond (vector? s)
... (seq? s) ...)", but this is a closed implementation.  If we want to
keep the implementation open for extension, you could use something like
the protocol-based code I wrote there, but it absolutely relies on these
abstract data types being represented as Java interfaces rather than other
protocols.

David says that in 10,000 lines of code, there hasn't yet been something
that required protocols to dispatch on other protocols, but in nearly the
same breath he says that a polymorphic last function is impractical because
of this limitation.  The difficulty, he notes, is that a hypothetical ILast
protocol can't be made to automatically work for all implementers of ISeq.
Every single person who ever wanted to implement ISeq would also have to
implement ILast.  I would argue that as soon as you're ruling out ideas
such as a polymorphic last function specifically because it would make it
too difficult to maintain in a protocol-based system, that is clear
evidence that indeed, we *are* running into a real limitation of protocols.

So, I would like to better understand this limitation, and brainstorm with
everyone about workarounds.

I have some thoughts and ideas about this, but I want to better understand
the ClojureScript architecture first.  David, could you walk me through the
implementation of nth, which is a very similar kind of function?  I was
able to find the part of the code on Github where you define an IIndexed
protocol which provides a protocol for nth.  However, I was unable to find
the place in the code where you implement nth in linear time for all those
who implement ISeq and faster for random-access collections.  Can you point
me to the relevant source code?  Is nth open to extension to other abstract
data types?  Is nth guaranteed to work and gain the default implementation
for new data types that implement ISeq?  Do coders need to remember to
implement IIndexed any time ISeq is implemented, and if so, how is that
documented?

Thanks!

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to