Wow, this thread was exhausting :) This reply is not to anyone in particular, 
just tagging on at the end (hint).

It is quite easy to come up to some part of Clojure, with some need, and some 
current perspective, and find it unsatisfying. It certainly is not perfect. But 
a good presumption is that there might be more context, more constraints, or 
more issues in play than one might recognize at first glance. 

Mark was most correct in identifying that the algorithmic complexity dominates 
this decision. As far as the functions being defined in terms of abstractions: 
while true, the abstractions are still something that could be refactored. They 
are a means, not an end.

History: 'last' is a Lisp function. In Common Lisp it operates on lists only. 
It is a function that, there, advertises slowness by its mere presence. Code 
using it has a presumption it will only be used on short lists, and in fact it 
generally is; in macros and things that process code. People reading that code 
can presume the same.

I do think that, in general, it is bad to have a single polymorphic function 
that, depending on the target arguments, transitions between different 
algorithmic complexity categories (N.B. that is not equivalent to using 
polymorphism to get better performance by leveraging some implementation 
specifics, it is a specific subset). 'nth' for seqs is a counterexample, was 
requested by the community, and I still think is somewhat of a mistake. At 
least, it would be good to also have an 'elt' with specific non-linear 
complexity (for the reasons I give below).

Usually, there is a 'fast' function and someone wants it to work on something 
that would be in a slower category. This case is the opposite, 'last' is slow 
and people want it to be faster where possible. The end result is the same.

Why not just be as polymorphic as possible? In Common Lisp, there is a set of 
functions that lets you use lists as associative maps. The performance is not 
good as things get larger (i.e the sky falls). While this made sense at one 
point in time (when there were only lists), is it still a good idea now? Should 
we have functions that expect maps accept lists? 

In my experience, having everything work on/with lists made it really easy to 
get a system together that worked on small data sets, only to have it crash and 
burn on larger ones. And then, making it perform well was extremely 
challenging. Some of that was because of the lack of interface-conforming 
implementations of e.g. hashmaps to swap in. but another category of problem 
was not being able to see what calls mattered for performance, when lists would 
still be ok etc. Thus Clojure 'forces' you to make some of these decisions 
earlier, and make them explicit. Even so, it is still highly polymorphic.

At the moment, I'm not sure it would be bad to have 'last' behave better for 
vectors et al while still promising in documentation to be not necessarily 
better than linear. But I do know this - it is seriously unimportant. We all 
have much better things to do, I hope, than argue over things like this. 

There is a perfectly adequate and well documented way to get the last element 
of a vector quickly, and code for which that matters can (and should, *even if 
last were made faster*) use it. Code for which it doesn't matter can use 'last' 
on vectors because - ipso facto *it doesn't matter*! People reading either code 
will know what is and isn't important, and that seems to matter most.

Rich

-- 
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