nargout can be emulated by (ab)using the iteration protocol on a
custom return type that will be accessed through tuple
assignment/destructuring.

Take this example:

tpl = (1,2)
a,b = tpl

the second line will call start(), done() and next() on tpl to extract
the two numbers.

So, for your use case:

type Result; output1; otherstate; end

function myfunc(x, y)
    return Result(x+y, (x, y))
end

my_expensive_func(r::Result)
    #compute output2
end

start(r::Result) = 1
done(::Result, i) = i > 2
function next(r::Result, i)
    if i == 1
        (r.output1, 2)
    elseif i == 2
        (my_expensive_func(r), 3)
    end
end

to get the first result, use this (note the coma):

a, = myfunc(4,5)

Hopefully this helps :-)
—Pierre-Yves


On Fri, Mar 6, 2015 at 8:47 PM, Tim Holy <tim.h...@gmail.com> wrote:
> I'll take it in the opposite direction of uniformity, and point out that
> another useful approach is to pass the optional output in as an argument:
>
> function myfunction!(output2, input1, input2, ...)
>     # do some calculations
>     if !isa(output2, Nothing)
>         for i = 1:n
>             output2[i] = ...
>         end
>     end
>     output1
> end
>
> output1 = myfunction!(nothing, x, params)
> g = Array(T, sz)
> output1 = myfunction!(g, x, params)
>
> This is used extensively in optimization, where output2 might be storage for
> the gradient.
>
> Best,
> --Tim
>
>
> On Friday, March 06, 2015 08:24:08 PM Milan Bouchet-Valat wrote:
>> Le jeudi 05 mars 2015 à 11:59 -0800, Pooya a écrit :
>> > Thanks for this clear explanation. If I do the following, is my
>> > function type still unstable? How do you compare the following
>> > solution to yours in terms of efficiency, style, etc?
>> >
>> > function compute_outputs(..., output2Flag)
>> >
>> >   # do some stuff, get x, y, and z
>> >   # compute output 1
>> >   output1 = ...
>> >   if output2Flag
>> >
>> >     # compute output 2
>> >     output2 = ...
>> >
>> >   else
>> >
>> >     output2 = SparseMatrixCSC[]  # the same type as output2 when it is
>> >
>> > computed
>> >
>> >   end
>> >   return output1, output2
>> >
>> > end
>>
>> This version indeed appears to be type-stable, so it should be quite
>> efficient. Users will also be able to write
>> a, b = compute_outputs(..., false)
>> or
>> a, = compute_outputs(..., false)
>> when they don't care about the second output. So it's not a bad design,
>> but returning a second output even when not needed isn't super
>> satisfying.
>>
>> Thus, maybe Steven's suggestion to create two separate functions is
>> better. Do you have any reason to think it's not practical for your
>> case?
>>
>> We should probably decide what's the most idiomatic solution, and
>> document it to ensure consistency. What do other people think?
>>
>>
>> Regards
>>
>> > On Thursday, March 5, 2015 at 10:58:02 AM UTC-5, Steven G. Johnson
>> >
>> > wrote:
>> >         On Wednesday, March 4, 2015 at 6:38:28 PM UTC-5, Pooya wrote:
>> >                 Thanks for your response. I am not sure what you mean
>> >                 by a lower-level subroutine. Is that a function inside
>> >                 another one? If yes, How does the scope of variables
>> >                 work for that?
>> >
>> >         From your description, right now you have:
>> >
>> >
>> >         function compute_two_outputs(...)
>> >
>> >                ...do some stuff, get x, y, and z....
>> >                ....use x, y, and z to compute output1....
>> >                ....use output1, x, y, and z to compute output2....
>> >
>> >               return output1, output2
>> >
>> >         end
>> >
>> >
>> >         Instead, if you don't always want to compute both outputs, but
>> >         still want to write the shared computations only once, you can
>> >         refactor the code to pull out the shared computations into
>> >         another function (that is "lower level" in the sense that
>> >         users won't normally call it directly):
>> >
>> >
>> >         function some_stuff(...)
>> >
>> >                ...do some stuff, get x, y, and z....
>> >                ....use x, y, and z to compute output1....
>> >                return output1,x,y,z
>> >
>> >         end
>> >
>> >
>> >         function compute_output1(...)
>> >
>> >               return some_stuff(...)[1]
>> >
>> >         end
>> >
>> >
>> >         function compute_two_outputs(...)
>> >
>> >                output1,x,y,z = some_stuff(...)
>> >                ....use output1, x, y, and z to compute output2....
>> >
>> >               return output1, output2
>> >
>> >         end
>

Reply via email to