Path: csiph.com!eternal-september.org!feeder.eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: Tim Rentsch
Newsgroups: comp.lang.c++
Subject: Re: Why does this work on Xcode ???
Date: Sat, 10 Aug 2019 09:29:17 -0700
Organization: A noiseless patient Spider
Lines: 99
Message-ID: <86pnld7zmq.fsf@mailhub.linuxsc.com>
References: <1b10612f-47b9-4097-be59-d00dec4a800b@googlegroups.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: reader02.eternal-september.org; posting-host="4bad90a7c43721789c432acb03dbc8ee"; logging-data="13248"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18NUHe5jeMnn6K5Bl1jdiAmKRpxJ0Dp3W8="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:Yu86J7QaRkRboUMtpgseoCT/xM8= sha1:8mUkhLc0LKjYwidK+sbiDZFkahI=
Xref: csiph.com comp.lang.c++:67530
Jorgen Grahn writes:
> On Wed, 2019-07-17, Alf P. Steinbach wrote:
>
>> On 17.07.2019 07:03, Bob Langelaan wrote:
>>
>>> Several of my students have submitted the following solution (or
>>> something very similar) for a recursive function to add the contents
>>> of an array:
>>
>> The presented code doesn't ?add the contents?, I guess that's just typo.
>>
>>
>>> // Returns true if the supplied value is found in the array of values
>>> // and false otherwise
>>> template
>>> bool isMember(const array & myArray, const int n, const type value)
>>> {
>>> if ( n < 0 )
>>> {
>>> return false;
>>> }
>>> else if ( myArray[n] == value )
>>> {
>>> return true;
>>> }
>>> return isMember( myArray, n - 1, value );
>>> }
>>
>> The two main problems with this function are:
>>
>> * Passing `value` by value may incur severe copying inefficiency.
>> * The tail recursion may easily consume all stack space and yield UB.
>
> It's also fairly sad and inelegant use of recursion, with the extra
> cursor being passed around. The way I learned recursion, you start by
> seeing an array as either empty, or having a head element, and then:
>
> // vaguely Haskell-like pseudo-code
> ismember(value, []) -> false
> ismember(value, head:tail) -> value==head || ismember(value, tail)
>
> My point is, I'm not sure the students will appreciate recursion
> properly based on that code, if that's the intention. (Perhaps not
> based on any C++ code.)
These comments strike me as somewhat odd. Certainly it is true
that recursive functions often offer a good fit to recursive data
types. That doesn't mean recursion is a bad fit in other cases.
On the contrary, using recursion often gives a definition that is
simpler and easier to understand than a non-recursive version. A
well-known example is finding the greatest common divisor of two
numbers, which might be written as follows (with gcd(0,0) to
return the value 1):
unsigned
gcd( unsigned a, unsigned b ){
return a == 0 ? b != 0 ? b : 1
: gcd( b%a, a );
}
Writing a nicely tail-recursive function often entails passing
arguments besides just the primary data item. This happens with
arrays in C and C++ because arrays are not recursive data types in
C or C++ (nor are they in many functional languages). Furthermore
we may want not one additional "cursor" but more than one. Here
is a function to determine if a sorted array contains a given
value:
bool
contains( int *v, size_t base, size_t limit, int item ){
if( base == limit ) return false;
size_t mid = base + (limit-base)/2;
if( v[mid] < item ) return contains( v, mid+1, limit, item );
if( v[mid] > item ) return contains( v, base, mid, item );
return true;
}
In later versions of C++ we might choose to write this function
differently, using 'span' (disclaimer: I am not an expert on
span!). Doing that would very likely give a nicer function. But
I wouldn't say the non-span version is "inelegant". It's just a
reflection of how the language-provided data types work. Do I
remember right that you are one of the people who is still
working (or forced to work) with C++11? Anyone in that boat
might choose a function definition like the one above, until such
time as better language facilities are available so it could be
re-written more attractively.
I guess my main point is that recursion is more broadly applicable
than just those situations where recursive data types are
involved. In fact, in languages like C and C++, it is much more
likely to encounter a good fit for recursion that does not make
use of recursive data types, simply because C and C++ typically do
not define data types recursively. Recursion is more fundamental
than just the cases where recursive data types are used.