I promised I won't post more on this thread. But Rich is here and I think I 
can grant myself an excuse to post just one more. End of it, I promise. :-)

First, although Rich does not think so, I myself feel this topic is very 
important as it is not just about "last", It touches some fundamental 
design principles. 

Then, please see my comments embedded in Rich's original message. And my 
comments are not long as I already said most of what I want to say before. 
Thank you.

On Sunday, July 1, 2012 2:17:07 PM UTC-4, Rich Hickey wrote:
>
> 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. 
>
>
True, but this applies both ways. So it is also possible to be satisfied 
with our current design with our current context and find out it does not 
fit later.

 

> 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. 
>
>  
In "list as map" example of Common Lisp, that in my view is not the fault 
of polymorphic design, that is because as you said a lack of it. (... 
because of the lack of interface-conforming implementations ...). If the 
polymorphic design were done right, then we should be able to swap in an 
efficient map implementation. I think we should learn the *right* lesson 
here.
  

> 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 
>
>
As a middle ground, maybe we can keep both type specific and polymorphic 
functions? For people who absolutely need to squeeze out the last drop of 
performance, the type specific function will save them some dispatching 
cost. But I myself would rather to have the most generic functions and tune 
my performance by using the right data structures.

Again, thank you.


 

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