Boost logo

Boost :

Subject: Re: [boost] painless currying
From: Simonson, Lucanus J (lucanus.j.simonson_at_[hidden])
Date: 2011-08-24 17:33:16


Dave Abrahams wrote:
> on Wed Aug 24 2011, Eric Niebler <eric-AT-boostpro.com> wrote:
>
>> On 8/24/2011 12:55 PM, Dave Abrahams wrote:
>>>
>>> on Wed Aug 24 2011, Eric Niebler <eric-AT-boostpro.com> wrote:
>>>
>>>> On 8/24/2011 4:28 AM, Thomas Heller wrote:
>>>>>
>>>>> However, the problem comes with function objects having
>>>>> operator() overloads with different arity. Another problem I
>>>>> couldn't solve yet is how to decide which overload gets curryied
>>>>> or not.
>>>>> Consider:
>>>>>
>>>>> struct foo
>>>>> {
>>>>> void operator()(int);
>>>>> void operator()(int, int);
>>>>> };
>>>>>
>>>>> curryable<foo> f;
>>>>> auto curried = f(1); // To curry or not to curry, that is the
>>>>> question
>>>>
>>>> As soon as enough arguments are collected to call the curried
>>>> function, it gets called. So in this case, f(1) calls
>>>> f::operator()(int).
>>>
>>> That's an asymmetry about most currying syntax that I never liked,
>>> at least for C++.
>>
>> Could you explain what you mean by asymmetry here? That my currying
>> code prefers one function over another based on the available
>> arguments?
>
> I mean this, for a ternary function f:
>
> f(x) => doesn't call f
> f(x)(y) => doesn't call f
> f(x)(y)(z) => calls f
>
> That last step looks asymmetric to me.
>
> In a lazy language, f(x)(y)(z) *doesn't* call f... until you actually
> use the result for something... which is more consistent-looking.
>
> I suppose the symmetrical non-lazy version looks like:
>
> f(x) => doesn't call f
> f(x)(y) => doesn't call f
> f(x)(y)(z) => doesn't call f
> f(x)(y)(z)() => calls f

I tend to agree, but can't we have both? What about if the lazy f implicitly converts to its return type through a casting operator? This way we can pass the return type of f(x)(y)(z) as a function object, but make lazy execution of the function object implicit.

   f(x) => doesn't call f
   f(x)(y) => doesn't call f
   result_type result = f(x)(y)(z) => calls f through operator(result_type)

If f had a void return type I guess we would have to force it's call with operator() and use of operator() would otherwise be optional. I suppose forgetting to force would be error prone if people are used to relying on the implicit conversion to force the function call. In general I see no reason not to make a nullary function object castable to its operator() return type, does the loss of type safety hurt us in this case? I like the simplicity of not having the extra () in the simple case where I want to get its result immediately. It may be more intuitive also, but I guess it could do more harm than good if it leads to astonishment.

Just thinking out loud,
Luke


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk