Mon, 21 Dec 2009 12:13:48 -0600, Andrei Alexandrescu wrote:

> Daniel de Kok wrote:
>> On 2009-12-19 21:04:32 +0100, Andrei Alexandrescu
>> <seewebsiteforem...@erdani.org> said:
>>> "This code is shown for its elegance rather than its efficiency. Using
>>> ++ in this way is not generally considered good programming practice."
>>>
>>> So if the code is inefficient and in poor programming practice, how in
>>> this blessed world could it count as elegant?
>> 
>> Well, it is elegant in that it is very readable, and as such provides
>> educational value.
> 
> I disagree. We don't want to educate people to write patently
> inefficient code and in poor programming practice.
> 
> When I was doing Windows programming, I noticed that many example in the
> documentation were written in terrible style. I also noticed that much
> of the production code I was working with was often stitched from
> documentation examples.
> 
>> There are very many examples in programming text books that may not be
>> efficient, but do show the solution to a problem elegantly.
> 
> Yeah, exponential-time Fibonacci and bubble sort come to mind.
> 
> In my mind "elegant" and "at a polynomial blowup in complexity" can't be
> reconciled anywhere outside a Turing machine introduction where
> everything is equivalent within a polynomial difference in time and
> space.
> 
>> E.g. consider list reversal in a recursive function or predicate. It is
>> easy to see that to reverse a list, you append the head to the reversed
>> tail. E.g.:
>> 
>> reverse([],[]).
>> reverse([H|T],R) :-
>>  reverse(T,RT),
>>  append(RT,[H],R).
>> 
>> Of course, this is very inefficient, since the program is doing (slow)
>> appends all the time, and is not tail-recursive. You can do it a lot
>> faster with an accumulator, but it makes the solution also less
>> understandable, and not something you'd want to present
>> students/readers immediately:
>> 
>> reverse(List,Reverse) :-
>>  reverse_aux(List,Reverse,[]).
>> 
>> reverse_aux([],List,List).
>> reverse_aux([H|T],List,List0) :-
>>  reverse_aux(T,List,[H|List0]).
> 
> Yah, I understand. But what you're really saying is that reverse offers
> either a simple implementation or an efficient implementation, but not
> both. That's hardly furthering my belief that FP has a crushing
> advantage over pretty much anything else.
> 
> In another thread, "retard" wrote in response to the comparison of the
> real quicksort in C and Haskell:
> 
> "What is so brilliant? Referential transparency is broken unless single-
> threadedness is forced through monadic computation or by some other
> means (uniqueness types comes to mind)."
> 
> I think that's a roundabout way of saying that functional programming is
> unable to express certain algorithms easily or at all.

I think one of the things that make good programming languages good is 
that they allow hiding the complexity behind abstractions. This is 
something I remember from the SICP lectures. This is the ideology behind 
pure functional and pure object oriented programming. Reliability is 
transitive - if the building blocks are good, you can't screw /those/ 
things on higher level. Things like referential transparency also give 
you truly modular isolation in this way. You can always find a loop hole 
in languages like D.

I think I've already read what you think about abstractions. After all, 
it's not really surprising why in "systems programming languages" like D 
one can more or less easily convert any high level expression into 
machine code in their head. On relatively low level it's benefical to 
always think in terms of machine code instructions, stack layouts, 
pointers etc.

But on higher level, performance is in many domains only a secondary 
goal. Reliability is the main goal. If there's an abstract data type such 
as a queue or a stack, you simply can't produce traditional stack 
overflows because the abstraction protects against that. The container 
code can be really ugly spaghetti internally - the abstraction works as a 
public interface.

Reply via email to