COW vs. in-place.

Oskar Linde oskar.lindeREM at OVEgmail.com
Thu Aug 3 09:21:16 PDT 2006


Sean Kelly wrote:
> Oskar Linde wrote:
>> Dave wrote:
>>> Reiner Pope wrote:
>>>>> Why not:
>>>>>
>>>>>     str = toupper(str);     // in-place
>>>>>     str = toupper(str.dup); // COW
>>
>> What is the advantage of redundantly assigning the result of an 
>> in-place function to itself? In my opinion, all in-place functions 
>> should have a void return type to avoid common mistakes such as:
>>
>> foreach(e; arr.reverse) { ... }
>> // OOPS, arr is now reversed
> 
> I like returning the mutated value so the function call can be embedded 
> in other code.  

I have already seen the above foreach error in others D code.
I believe it is good library design to clearly mark functions with 
side-effects. Giving them a void return type will prevent any mistake of 
the following kind (assume toupper is in-place modifying as well as 
returning):

func(toupper(mystring));
func(arr.reverse);

where the side effect was unintended.
could those be errors: ?

arr2 = arr1.reverse;

toupper(mystring) ~ mystring;

> And arr.reverse is already a built-in mutating function, 
> according to the spec.

Yes. I find that unfortunate and inconsistent with how Phobos is 
designed. Luckily, arr.sort and arr.reverse are not callable as 
arr.sort() and arr.reverse(), so they really don't look like functions.

>> .dup followed by calling an in-place function is certainly ok, but in 
>> those cases, an ordinary functional (non-in-place) function would have 
>> been more efficient.
> 
> Why?

What I meant was that .dup + inplace will never be more efficient than a 
copying algorithm. In-place algorithms are often more complicated. If 
you want a copy anyway, it is more efficient to use a copying algorithm. 
As an example, consider stable sorting, where efficient copying 
algorithms are trivial.

Re: Library design

I would like to see both copying and in-place versions of algorithms 
where it makes sense, but only one behavior should be default. That 
default should be consistent throughout the standard library and 
preferably be recommended in an official style guide for third party 
libraries to follow.

I see two valid designs:


1. in-place default, copying algorithms specially named
-------------------------------------------------------

Design:
void toUpper(char[] str); // in-place
char[] toUpperCopy(char[] str); // copy

Pros:
* in-place is often more efficient and therefore default.
* many functions are imperative verbs, and as such one expects them to 
be modifying
* Similar to how the C++ STL is designed
Cons:
* many functions can not be expressed in-place (example: UTF-8 toUpper)


2. copying default, in-place versions specially named
-----------------------------------------------------

Design:
void toUpperInPlace(char[] str); // in-place
char[] toUpper(char[] str); // copy

Pros:
* copying is safer, and is therefore a better default
* in-place is an optimization and would stand out as such
* default is functional (no-side effects), side effects stand out
* people used to functional style programming would not find any
surprises
* all functions can be defined as copying functions
* how many popular languages are designed (Ruby, Python, php, all 
"functional" languages, etc...)
Cons:
* could confuse people, lead to silent errors:
toupper(str); // doesn't change str
cos(x); // doesn't change x ;)

For the record, I am in favor of number 2 and that would have biased the 
arguments above.

/Oskar



More information about the Digitalmars-d mailing list