<p dir="auto">I would like to propose allowing tuples of functions to be be <code class="notranslate">callable</code> and have the syntax:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="(f,g)(x) = (f(x),g(x))"><pre class="notranslate"><code class="notranslate">(f,g)(x) = (f(x),g(x))
</code></pre></div>
<p dir="auto">At the moment this is disallowed with an error, e.g.:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="x = collect(1:10);
(minimum,maximum)(x)
julia&gt; ERROR: MethodError: 
objects of type Tuple{typeof(minimum),typeof(maximum)} are not callable
Stacktrace:
 [1] top-level scope at REPL[7]:1"><pre class="notranslate"><code class="notranslate">x = collect(1:10);
(minimum,maximum)(x)
julia&gt; ERROR: MethodError: 
objects of type Tuple{typeof(minimum),typeof(maximum)} are not callable
Stacktrace:
 [1] top-level scope at REPL[7]:1
</code></pre></div>
<p dir="auto">Another use for this would be to unpack the keys and values of a dictionary in a single line:<br>
<code class="notranslate">k,v = (keys, values)(mydict::Dict)</code></p>
<ol dir="auto">
<li>
<p dir="auto">I do not know where <code class="notranslate">callable</code> is specified. Searching the docs for <code class="notranslate">callable</code> or in the help <code class="notranslate">?callable</code> does not give anything concrete about how to allow something to be callable.</p>
</li>
<li>
<p dir="auto">How should broadcasting work? I think a reasonable proposal is <code class="notranslate">(f,g).(x) == (f.(x), g.(x))</code>. Is this ambiguous or not desirable for a reason I cannot foresee?</p>
</li>
<li>
<p dir="auto">Since <code class="notranslate">f</code> and <code class="notranslate">g</code> would be accessing the same input, and likely be doing similar operations, this introduces a performance issues. It makes it really easy to write non-performant code. My assumption was that there would be a lot of duplicated work if e.g. <code class="notranslate">f</code> and <code class="notranslate">g</code> both look through <code class="notranslate">x</code> separately, they should know to share common work.</p>
</li>
</ol>
<p dir="auto">This was motivated by the <code class="notranslate">(minimum,maximum)(x)</code> example. There is an existing function for this, <code class="notranslate">extrema</code> which should return the same result faster:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="using BenchmarkTools

(T::Tuple{typeof(minimum),typeof(maximum)})(x) = (minimum(x),maximum(x))

x = rand(10^3);
@btime (minimum,maximum)($x)
@btime extrema($x)"><pre class="notranslate"><code class="notranslate">using BenchmarkTools

(T::Tuple{typeof(minimum),typeof(maximum)})(x) = (minimum(x),maximum(x))

x = rand(10^3);
@btime (minimum,maximum)($x)
@btime extrema($x)
</code></pre></div>
<p dir="auto">On Julia-1.1:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="julia&gt; @btime (minimum,maximum)($x)
  4.593 μs (0 allocations: 0 bytes)
(0.0010074908627801804, 0.9977385773243437)

julia&gt; @btime extrema($x)
  2.649 μs (0 allocations: 0 bytes)
(0.0010074908627801804, 0.9977385773243437)"><pre class="notranslate"><code class="notranslate">julia&gt; @btime (minimum,maximum)($x)
  4.593 μs (0 allocations: 0 bytes)
(0.0010074908627801804, 0.9977385773243437)

julia&gt; @btime extrema($x)
  2.649 μs (0 allocations: 0 bytes)
(0.0010074908627801804, 0.9977385773243437)
</code></pre></div>
<p dir="auto">So you can see that this callable tuple is twice as slow. EXCEPT!</p>
<p dir="auto">On Julia-1.3:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="julia&gt; @btime (minimum,maximum)($x)
  1.835 μs (0 allocations: 0 bytes)
(1.8361594563476302e-5, 0.9999551648541347)

julia&gt; @btime extrema($x)
  2.651 μs (0 allocations: 0 bytes)
(1.8361594563476302e-5, 0.9999551648541347)"><pre class="notranslate"><code class="notranslate">julia&gt; @btime (minimum,maximum)($x)
  1.835 μs (0 allocations: 0 bytes)
(1.8361594563476302e-5, 0.9999551648541347)

julia&gt; @btime extrema($x)
  2.651 μs (0 allocations: 0 bytes)
(1.8361594563476302e-5, 0.9999551648541347)
</code></pre></div>
<p dir="auto">Ummm. So now the tuple <code class="notranslate">(minimum,maximum)</code> is faster than <code class="notranslate">extrema</code>? I don't understand this. Some threading magic?</p>
<p dir="auto">Anyway I think this is a general problem, is the compiler smart enough to let <code class="notranslate">f</code> and <code class="notranslate">g</code> know about the shared work between <code class="notranslate">f</code> and <code class="notranslate">g</code> and use them together?</p>
<p dir="auto">I was going to propose explicitly dispatching to more efficient joint methods, e.g. <code class="notranslate">(T::Tuple{typeof(minimum),typeof(maximum)})(x) = extrema(x)</code> but not only is this ugly, very specific, and hopefully could be automatically made efficient by the compiler. It is also, as demonstrated above, less efficient than <code class="notranslate">(minimum(x),maximum(x))</code> currently!</p>
<ol start="4" dir="auto">
<li>I don't know what to do in the case that <code class="notranslate">f</code> mutates <code class="notranslate">x</code>, or if we should do anything. If it is literally the case that <code class="notranslate">(f,g)(x) = (f(x),g(x))</code> then I guess the order of these two matter. But if its possible to do these two functions in parallel, it might be a problem. I also don't know how that might affect shared work.</li>
</ol>
<p dir="auto">I would like to help implement this. I think it looks like setting up methods that look like</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="(T::Tuple{f::Callable,g::Callable})(x) = (f(x),g(x))"><pre class="notranslate"><code class="notranslate">(T::Tuple{f::Callable,g::Callable})(x) = (f(x),g(x))
</code></pre></div>
<p dir="auto">But as I said at the top, I don't know what decides if a type is callable.</p>
<p dir="auto"><a href="http://julia.readthedocs.org/en/latest/search/?q=ext&amp;check_keywords=yes&amp;area=default#" rel="nofollow">http://julia.readthedocs.org/en/latest/search/?q=ext&amp;check_keywords=yes&amp;area=default#</a></p>
<p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow" href="https://cloud.githubusercontent.com/assets/6168860/7942931/bfdb1780-0937-11e5-950c-28b9b08f9c3c.png"><img src="https://cloud.githubusercontent.com/assets/6168860/7942931/bfdb1780-0937-11e5-950c-28b9b08f9c3c.png" alt="screenshot from 2015-06-02 14-56-30" style="max-width: 100%;"></a></p>