<p dir="auto">Following the discussion on Arrays in Julia 0.5 <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="106669708" data-permission-text="Title is private" data-url="https://github.com/JuliaLang/julia/issues/13157" data-hovercard-type="issue" data-hovercard-url="/JuliaLang/julia/issues/13157/hovercard" href="https://github.com/JuliaLang/julia/issues/13157">#13157</a> , I want to suggest including new operators for the tensor sum (or direct sum) operation and for the tensor product (outer product).</p>
<p dir="auto">The tensor sum (direct sum) is a way of combining both vector spaces as well as tensors (vectors, matrices or higher order arrays) of the same order. The tensor sum of two vector spaces V1 ⊕ V2 simply concatenates their two bases. Similarly, the tensor sum of two vectors v1 ⊕ v2 is their concatenation, <code class="notranslate">vcat(v1,v2)</code>. For higher order tensors (higher dimensional arrays), all the vector spaces associated with each dimension are concatenated, and the elements of the arrays are filled in their original positions, resulting in a sparse (block diagonal) tensor. For example, the tensor sum of two matrices A ⊕ B is <code class="notranslate">[A 0; 0 B]</code>. Care would need to be taken for row vectors stored as 1-by-n arrays, but hopefully this will be resolved separately in Julia 0.5. For tensor sum, I suggest we use the usual symbol <code class="notranslate">⊕</code> (use <code class="notranslate">\oplus</code> in the REPL), but we could also consider <code class="notranslate">++</code> or other operations (please suggest). The tensor sum operator <em>might</em> be useful in other concatenation contexts, such as string concatenation (since ⊕ is non-commutative and is basically the correct monoid for concatenating vectors of characters), but this is not the main point at this stage.</p>
<p dir="auto">The tensor product (outer product) on vector spaces V1 ⊗ V2 creates a new basis with elements that are all possible outer products of the basis elements of V1 and of V2, and so the dimension of the resulting vector space becomes the product of the two individual dimensions. Julia already implements <code class="notranslate">kron()</code> which is the same idea, but restricted to only vectors and matrices. We could generalize <code class="notranslate">kron</code> and use <code class="notranslate">⊗</code> (<code class="notranslate">\otimes</code> in the REPL) or <code class="notranslate">**</code> (or something else) to implement this. Tensor products might be similar to other operations in other contexts - for example the outer join in relational algebra behaves similarly, so we could implement that for <code class="notranslate">DataFrame</code>s.</p>
<p dir="auto">Tensors and multilinear algebra are described by bi-monoidal categories (with the two monoids ⊗ and ⊕) so these to operations will make that a little simpler to write and reason about. Besides, these operators may have use in other fields where concatenation or outer products make sense. What is the policy on adding new operators to Julia? Is this frowned upon? Can we use unicode symbols, or must we continue with multiple ASCII symbols (which I find a bit ugly...)? Does anyone else think this is useful? If the community wants this feature, I could work on it and generate a PR (though the parser confuses me...)</p>
<p dir="auto">It appears that overwriting a function defined within another function can cause strange ordering issues.  MWE:</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="function do_test()
    function innerfunc()
        println(stderr, &quot;innerfunc&quot;)
    end
    println(stderr, &quot;pre-innerfunc&quot;)
    innerfunc()
    println(stderr, &quot;post-innerfunc&quot;)

    # Overwrite innerfunc
    innerfunc() = nothing
    println(&quot;innerfunc is now overwritten&quot;)
end

do_test()"><pre class="notranslate"><span class="pl-k">function</span> <span class="pl-en">do_test</span>()
    <span class="pl-k">function</span> <span class="pl-en">innerfunc</span>()
        <span class="pl-c1">println</span>(<span class="pl-c1">stderr</span>, <span class="pl-s"><span class="pl-pds">"</span>innerfunc<span class="pl-pds">"</span></span>)
    <span class="pl-k">end</span>
    <span class="pl-c1">println</span>(<span class="pl-c1">stderr</span>, <span class="pl-s"><span class="pl-pds">"</span>pre-innerfunc<span class="pl-pds">"</span></span>)
    <span class="pl-c1">innerfunc</span>()
    <span class="pl-c1">println</span>(<span class="pl-c1">stderr</span>, <span class="pl-s"><span class="pl-pds">"</span>post-innerfunc<span class="pl-pds">"</span></span>)

    <span class="pl-c"><span class="pl-c">#</span> Overwrite innerfunc</span>
    <span class="pl-en">innerfunc</span>() <span class="pl-k">=</span> <span class="pl-c1">nothing</span>
    <span class="pl-c1">println</span>(<span class="pl-s"><span class="pl-pds">"</span>innerfunc is now overwritten<span class="pl-pds">"</span></span>)
<span class="pl-k">end</span>

<span class="pl-c1">do_test</span>()</pre></div>
<p dir="auto">Expected output:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="pre-innerfunc
innerfunc
post-innerfunc
innerfunc is now overwritten"><pre class="notranslate"><code class="notranslate">pre-innerfunc
innerfunc
post-innerfunc
innerfunc is now overwritten
</code></pre></div>
<p dir="auto">Actual output:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="pre-innerfunc
post-innerfunc
innerfunc is now overwritten"><pre class="notranslate"><code class="notranslate">pre-innerfunc
post-innerfunc
innerfunc is now overwritten
</code></pre></div>
<p dir="auto">It appears that the optimizer records the final value of <code class="notranslate">innerfunc()</code> and completely disregards the original value:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="julia&gt; @code_lowered do_test()
CodeInfo(
1 ─      innerfunc = %new(Main.:(var&quot;#innerfunc#3&quot;))
│        Main.println(Main.stderr, &quot;pre-innerfunc&quot;)
│        (innerfunc)()
│        Main.println(Main.stderr, &quot;post-innerfunc&quot;)
│   %5 = Main.println(&quot;innerfunc is now overwritten&quot;)
└──      return %5
)"><pre class="notranslate"><code class="notranslate">julia&gt; @code_lowered do_test()
CodeInfo(
1 ─      innerfunc = %new(Main.:(var"#innerfunc#3"))
│        Main.println(Main.stderr, "pre-innerfunc")
│        (innerfunc)()
│        Main.println(Main.stderr, "post-innerfunc")
│   %5 = Main.println("innerfunc is now overwritten")
└──      return %5
)
</code></pre></div>
<p dir="auto">This is reproducible on every release of from 1.0 to <code class="notranslate">master</code>, I didn't bother looking farther back than 1.0.</p>