October 25, 2010
Dnia 25-10-2010 o 21:20:24 Tomek Sowiński <just@ask.me> napisał(a):

> (Map, Filter, Reduce)

reduce is of course not a range ;)

-- 
Tomek
October 25, 2010
Tomek S.:

> You're right. Still, modularity is a valid point.

This is a general and interesting design topic. The short answer is that a real language is designed taking into account different trade-offs.

Modularity is important, and Andrei surely likes it. Modularity means the ability to combine small parts to create many different complex systems. To do this the subsystems must interact clearly with each other, they must lack too many corner cases, and of course they need a common flexible interface. As I have recently read, in a modular system "the surprises will be pleasant ones".

On the other hand modularity has some disadvantages too. To be clean those interfaces among subsystems must often be hi-level, this means they may be not fully efficient (unless your compiler is very smart, as the most optimizing compiler, the Stalin Scheme compiler). Another disadvantage is that you have to build common higher order systems over and over again, and sometimes you need some brain and time to build them well.

To avoid this last problem a well designed system usually offers you pre-built higher order systems, made with the elementary components, that you may just use. In some situations very common usage patterns deserve to be encapsulated into handy forms.

So, if you have one of the most used high order functions (map), if its usage often enough deals with mapping functions that work on more than one range of items for its arguments, and if the current way to perform this operation from elementary components produces a not so readable syntax, then practicality asks for for a less modular but more handy design of map :-)

Few more examples of this trade-off below.

----------------

I have even (weakly) asked for amap()/afilter() functions, that are just array(map(...)) and array(filter(...)), because those are very common patterns in my code. I am still not sure adding amap/afilter to Phobos is a good idea, it just reduces the number of parenthesis a little, so it decreases noise in the code.

----------------

Recently in Bugzilla I have asked for sorted()/schwartzSorted(), in this case my desire is stronger, because they save a bit more than just few chars, they are expressions:
http://d.puremagic.com/issues/show_bug.cgi?id=5076

----------------

A similar thread has recently come up in the D.learn newsgroup: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=22413

This person has asked for a way to remove the first item in an array given not the item index (found with indexOf), but the item itself.

Python2 too has those two different ways to remove an item from a list (array), by inded and by item:

>>> arr = ["a", "b", "c", "d"]
>>> arr.remove("x")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list
>>> arr.index("c")
2
>>> arr.remove("c")
>>> arr
['a', 'b', 'd']
>>> del arr[1]
>>> arr
['a', 'd']


This composed operation (list.remove in Python) is useful in D both because it's a common need, and because it saves the testing code in the middle (between the index and the del, to be sure the item is present). Well, the test is done anyway, but it's done after the single operation, this is a little better.

In Python the list.remove raises an exception if the item is missing. In D this function may throw an exception or return a false boolean (exceptions are safer, but less efficient, this is another trade-off. In some situations you may even add both functions, one that throws exceptions and one that returns true/false).

In D a combined function like the Python list.remove() one also avoids possible troubles caused by the fact that indexOf() returns a signed integer, and while the delete function accepts signed integers too, then I think inside it compares them to a unsigned length and this may cause troubles :-(

You may compile this wrong program in release mode, to see it:


import std.algorithm: remove, indexOf;
import std.stdio: writeln;
void main() {
    int[] a1 = [3, 5, 7, 8];
    auto pos = a1.indexOf(11);
    writeln(pos); // -1
    int[] a2 = a1.remove(pos);
    writeln(a2);
}


Partially related problem, this is part of the docs of std.algorithm:

>The original array has remained of the same length because all functions in std.algorithm only change content, not topology. The value 8 is repeated because std.algorithm.move  was invoked to move elements around and on integers move simply copies the source to the destination. To replace a with the effect of the removal, simply assign a = remove(a, 1). The slice will be rebound to the shorter array and the operation completes with maximal efficiency.<

This is bug-prone, but maybe there is no way to avoid this behaviour, because in D arrays aren't true reference types.

Bye,
bearophile
1 2
Next ›   Last »