challenge: implement the max function
Andrei Alexandrescu (See Website For Email)
SeeWebsiteForEmail at erdani.org
Sun Jan 21 18:25:50 PST 2007
Frits van Bommel wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Here's a simple challenge: implement the max function. Requirements:
>>
>> a) generic
>> b) efficient
>> c) preserve lvalueness when possible such that one can write e.g.
>>
>> max(arr[0], arr[1]) *= 0.9;
>>
>> d) should accept two or more arguments
>> e) should return the "smartest" type, e.g. max of an unsigned int and
>> unsigned long should return unsigned long
>> f) short and easy to understand
>>
>> I don't think it's possible to implement the function to the spec in
>> current D, so designs are allowed to invent new features, as long as
>> they define them thoroughly.
>
>
> Some first thoughts:
>
> Presumably, (b) is only required when using full optimization options?
That is correct.
> I was going to ask "What is the 'smartest type' for the max of long and
> ulong?" but then I thought of the answer: ulong. Since the ulong is
> non-negative, the max of a long an an ulong will always be non-negative
> itself.
Exactly right. max makes for a great example in type manipulation
abilities because it's simple yet gives the type system a good workout.
> (c) & (e) are exclude each other in current D since return values are
> always rvalues, and a forwarding struct goes against requirement (e).
That's why you are kindly invited to invent the feature(s) that you find
fit to comply to the spec.
> C++-like references won't work even if added, since the return type
> needs to be determined at compile time. This means you can't return an
> ulong& for max(uint, ulong) since if the uint happens to be larger you
> can't create the ulong& return value from the uint parameter.
True. But read (c) again: there is a "where possible". When the types
are different, you always return an rvalue. It's not possible to return
an lvalue, because you don't know statically which argument is larger.
> Adding implicit casts and bending requirement (e) a little to return a
> forwarding struct that implicitly converts to the wanted type is another
> option.
> This will probably breaks requirement (f) because of too much required
> operator overloading.
> Also, you'll need to perform runtime checks for each operation if there
> were multiple types and you want to preserve lvalue-ness. This will
> likely break requirement (b).
> That last objection could perhaps be mitigated by using a forwarding
> class instead of a struct though; runtime checks could then be replaced
> by virtual function calls. If that's efficient enough (b) is preserved.
This reasoning strays a bit away from the spec because it wants to do
(c) too often.
> Overall, I don't think this is possible in any statically typed
> programming language I know. I don't think even a C preprocessor macro
> can fulfill both (c) and (e) unless that "when possible" in (c) means
> "when possible in the language" instead of "when passed lvalues".
Heck, I did it in C++. It takes some hundred plus lines of code though
:o). The obvious purpose of my challenge is to find what it takes to
make it a trivial few-liner in D.
Andrei
More information about the Digitalmars-d
mailing list