October 20, 2008
downs wrote:
> Lars Kyllingstad wrote:
>> downs wrote:
>>> Lars Kyllingstad wrote:
>>>> Hello,
>>>>
>>>> There is a feature I would very much like to see in D. I don't know if
>>>> it has been discussed before, or whether is's even possible, but I'm
>>>> just going to throw it out here. Please tell me what you think.
>>>>
>>>> Suppose you have a function that takes a certain number of arguments,
>>>> say
>>>>
>>>>   creal f(real x, int i);
>>>>
>>>> Then it would be neat if one could specify just some of the arguments,
>>>> and have the result be a pointer to a function that takes the remaining
>>>> arguments. To clarify, the type of
>>>>
>>>>   f(real, 2)
>>>>
>>>> would then be
>>>>
>>>>   creal function(real)
>>>>
>>>> Why would this be nice? As an example, say you have a function that
>>>> calculates the derivative of another function at a certain point:
>>>>
>>>>   real derivative(real function(real), real z);
>>>>
>>>> With the above notation I can use this for functions of several
>>>> variables:
>>>>
>>>>   real f(real x, real y) { ... };
>>>>   auto dfdx = derivative( f(real, 1.23), 4.56 );
>>>>
>>>> As an added bonus, I can even differentiate with respect to y:
>>>>
>>>>   auto dfdy = derivative( f(1.23, real), 4.56 );
>>>>
>>>> Already, there are several ways to do similar things, but in my opinion
>>>> they are not as good:
>>>>
>>>> 1. Use templates
>>>> Nice, but only works when the pre-specified arguments are known at
>>>> compile time. (Or is there some trick I don't know about?)
>>>>
>>>> 2. Use functors
>>>> This works, but leads to worse performance and is in my opinion less
>>>> elegant. One has to type a lot of code just to define simple functions.
>>>>
>>>> 3. Use wrapper functions
>>>> Same problems as (2), and also leads to use of global variables.
>>>>
>>>> 4. The GSL way: Pass remaining arguments in a void* pointer.
>>>> Example:
>>>>
>>>>   real derivative(real function(real, void*), real z);
>>>>
>>>> IMO, this is UGLY, not to mention un-D-ish.
>>>>
>>>>
>>>> I mainly use D for numerical computations, hence the examples above. But
>>>> I'm sure there are many other uses for such a feature. What do you
>>>> think?
>>>>
>>>> -Lars
>>> How about an implicit functor?
>>>
>>> creal f(real x, int i);
>>>
>>> auto f2 = bind(&f, _0, 2); // I think
>>>
>>> auto f2 = &f /rfix/ 2; // tools version
>>>
>>> This creates a functor on the heap, and is indeed slower, but it's
>>> more elegant than you make it sound :)
>> Ok, but say I want to do this several times:
>>
>>   for (real y=yStart; y<=yEnd; y+=yStep)
>>       derivative(&f /rfix/ y, 1.23);
>>
>> Would it be any faster if your /rfix/ (or a similar function) created
>> the functor on the stack instead?
>>
>> -Lars
> 
> Yes, but how could it possibly do that?
> 
> After all, then the data would become invalid on scope exit, which is exactly what we're trying to avoid!

I'm not sure I understand. Wouldn't it be possible to do something like this:

  struct FunctionWrapper
  {
    ...
    SomeType opCall(...) { ... }
  }

and then have /rfix/ (or bind) return a FunctionWrapper? Of course it would have to return by value instead of returning a pointer, since whatever is pointed to will be lost on scope exit. If there are no pointers to stack data inside the struct there shouldn't be a problem. Don't know if it's possible to avoid this, though.

But perhaps the cost of returning a (possibly large) struct by value would outweigh the cost of calling functors on the heap? I guess it depends on how many times a single functor is called, compared to how often a new one is created.

-Lars
1 2
Next ›   Last »