<p dir="auto"><strong>repro:</strong></p>
<ol dir="auto">
<li>clean checkout at master (<a class="commit-link" data-hovercard-type="commit" data-hovercard-url="https://github.com/JuliaLang/julia/commit/2c9e051c460dd9700e6814c8e49cc1f119ed8b41/hovercard" href="https://github.com/JuliaLang/julia/commit/2c9e051c460dd9700e6814c8e49cc1f119ed8b41"><tt>2c9e051</tt></a>)</li>
<li><code class="notranslate">make</code></li>
</ol>
<p dir="auto"><strong>expected:</strong></p>
<p dir="auto">successful build</p>
<p dir="auto"><strong>actual:</strong></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="...
LibCURL  ──────────  0.361519 seconds
Downloads  ────────  0.605942 seconds
Pkg  ──────────────  3.760104 seconds
LazyArtifacts  ────  0.002615 seconds
Stdlibs total  ──── 30.568599 seconds
Sysimage built. Summary:
Total ───────  51.765127 seconds 
Base: ───────  21.193995 seconds 40.9426%
Stdlibs: ────  30.568599 seconds 59.0525%
    JULIA usr/lib/julia/sys-o.a
/bin/sh: line 1: 62349 Segmentation fault: 11  JULIA_BINDIR=/Users/vilterp/code/j-test/julia/usr/bin WINEPATH=&quot;/Users/vilterp/code/j-test/julia/usr/bin;$WINEPATH&quot; /Users/vilterp/code/j-test/julia/usr/bin/julia -O3 -C &quot;native&quot; --output-o /Users/vilterp/code/j-test/julia/usr/lib/julia/sys-o.a.tmp --startup-file=no --warn-overwrite=yes --sysimage /Users/vilterp/code/j-test/julia/usr/lib/julia/sys.ji /Users/vilterp/code/j-test/julia/contrib/generate_precompile.jl 1
*** This error is usually fixed by running `make clean`. If the error persists, try `make cleanall`. ***
make[1]: *** [/Users/vilterp/code/j-test/julia/usr/lib/julia/sys-o.a] Error 1
make: *** [julia-sysimg-release] Error 2"><pre class="notranslate"><code class="notranslate">...
LibCURL  ──────────  0.361519 seconds
Downloads  ────────  0.605942 seconds
Pkg  ──────────────  3.760104 seconds
LazyArtifacts  ────  0.002615 seconds
Stdlibs total  ──── 30.568599 seconds
Sysimage built. Summary:
Total ───────  51.765127 seconds 
Base: ───────  21.193995 seconds 40.9426%
Stdlibs: ────  30.568599 seconds 59.0525%
    JULIA usr/lib/julia/sys-o.a
/bin/sh: line 1: 62349 Segmentation fault: 11  JULIA_BINDIR=/Users/vilterp/code/j-test/julia/usr/bin WINEPATH="/Users/vilterp/code/j-test/julia/usr/bin;$WINEPATH" /Users/vilterp/code/j-test/julia/usr/bin/julia -O3 -C "native" --output-o /Users/vilterp/code/j-test/julia/usr/lib/julia/sys-o.a.tmp --startup-file=no --warn-overwrite=yes --sysimage /Users/vilterp/code/j-test/julia/usr/lib/julia/sys.ji /Users/vilterp/code/j-test/julia/contrib/generate_precompile.jl 1
*** This error is usually fixed by running `make clean`. If the error persists, try `make cleanall`. ***
make[1]: *** [/Users/vilterp/code/j-test/julia/usr/lib/julia/sys-o.a] Error 1
make: *** [julia-sysimg-release] Error 2
</code></pre></div>
<p dir="auto"><strong>context</strong></p>
<ul dir="auto">
<li>macOS: 11.5.2. intel x64</li>
<li>clang:</li>
</ul>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="clang -v
Apple clang version 13.0.0 (clang-1300.0.29.3)
Target: x86_64-apple-darwin20.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin"><pre class="notranslate"><code class="notranslate">clang -v
Apple clang version 13.0.0 (clang-1300.0.29.3)
Target: x86_64-apple-darwin20.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
</code></pre></div>
<p dir="auto">I've addressed this feature multiple times, but never really got feedback on it, so I decided to open an issue for it, as I keep coming back to it as a very elegant solution to many problems.<br>
I hope you can answer at least, how feasible this is, what needs to be done for it (so that I can maybe implement it myself, if no one has the time), or explain me why this is a silly idea.</p>
<h5 dir="auto">What I want:</h5>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="# Introducing a new type, in a typealias like fashion.
# first syntax idea
hardtypealias RGB{T &lt;: FloatingPoint} NTuple{3, T}
# second syntax idea
immutable Meter{T &lt;: Real} &lt;: T
# third syntax idea
concrete FixedMatrix{T, M, N} &lt;: NTuple{NTuple{M, T}, N} # in constrast to abstract"><pre class="notranslate"><span class="pl-c"><span class="pl-c">#</span> Introducing a new type, in a typealias like fashion.</span>
<span class="pl-c"><span class="pl-c">#</span> first syntax idea</span>
hardtypealias RGB{T <span class="pl-k">&lt;:</span> <span class="pl-c1">FloatingPoint</span>} NTuple{<span class="pl-c1">3</span>, T}
<span class="pl-c"><span class="pl-c">#</span> second syntax idea</span>
immutable Meter{T <span class="pl-k">&lt;:</span> <span class="pl-c1">Real</span>} <span class="pl-k">&lt;:</span> <span class="pl-c1">T</span>
<span class="pl-c"><span class="pl-c">#</span> third syntax idea</span>
concrete FixedMatrix{T, M, N} <span class="pl-k">&lt;:</span> <span class="pl-c1">NTuple{NTuple{M, T}, N}</span> <span class="pl-c"><span class="pl-c">#</span> in constrast to abstract</span></pre></div>
<p dir="auto">Intended semantic: The first type (e.g. RGB) is a either subtype of the second (e.g NTuple), or has the type Union(RGB, NTuple).<br>
I'm not sure what makes more sense. But it should solve the following problem:</p>
<blockquote>
<p dir="auto">There is an already existing type and one wants to add functions to it, without adding them to the original type.</p>
</blockquote>
<p dir="auto">This behavior is wanted in a myriad of cases and I've seen workarounds for this situation in many packages (including mine).</p>
<h3 dir="auto">Examples</h3>
<p dir="auto">A few examples, which can be elegantly implemented with this feature, which assume, that NTuple implements common, simd accelerated, vector operations</p>
<h4 dir="auto">Adding functions to an existing type:</h4>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="# under the assumption, that NTuple implements common vector operations
immutable RGB{T} &lt;: NTuple{3, T}

# under the assumption, that getfield can be extended
Base.getfield(c::RGB, ::Field{:r}) = c[1]
Base.getfield(c::RGB, ::Field{:g}) = c[2]
Base.getfield(c::RGB, ::Field{:b}) = c[3]
# which gives you the access to RGB which you'd expect from it.
# could also be implemented with a macro: @accessors RGB :r =&gt; 1, :g =&gt; 2, :b =&gt; 3 
# So this works:
a = RGB(0.1,0.2,0.3)
a+a # is implemented by NTuple
a.r # implemented by RGB
#Should not work:
(1,2,3).r"><pre class="notranslate"><span class="pl-c"><span class="pl-c">#</span> under the assumption, that NTuple implements common vector operations</span>
immutable RGB{T} <span class="pl-k">&lt;:</span> <span class="pl-c1">NTuple{3, T}</span>

<span class="pl-c"><span class="pl-c">#</span> under the assumption, that getfield can be extended</span>
Base<span class="pl-k">.</span><span class="pl-en">getfield</span>(c<span class="pl-k">::</span><span class="pl-c1">RGB</span>, <span class="pl-k">::</span><span class="pl-c1">Field{:r}</span>) <span class="pl-k">=</span> c[<span class="pl-c1">1</span>]
Base<span class="pl-k">.</span><span class="pl-en">getfield</span>(c<span class="pl-k">::</span><span class="pl-c1">RGB</span>, <span class="pl-k">::</span><span class="pl-c1">Field{:g}</span>) <span class="pl-k">=</span> c[<span class="pl-c1">2</span>]
Base<span class="pl-k">.</span><span class="pl-en">getfield</span>(c<span class="pl-k">::</span><span class="pl-c1">RGB</span>, <span class="pl-k">::</span><span class="pl-c1">Field{:b}</span>) <span class="pl-k">=</span> c[<span class="pl-c1">3</span>]
<span class="pl-c"><span class="pl-c">#</span> which gives you the access to RGB which you'd expect from it.</span>
<span class="pl-c"><span class="pl-c">#</span> could also be implemented with a macro: @accessors RGB :r =&gt; 1, :g =&gt; 2, :b =&gt; 3 </span>
<span class="pl-c"><span class="pl-c">#</span> So this works:</span>
a <span class="pl-k">=</span> <span class="pl-c1">RGB</span>(<span class="pl-c1">0.1</span>,<span class="pl-c1">0.2</span>,<span class="pl-c1">0.3</span>)
a<span class="pl-k">+</span>a <span class="pl-c"><span class="pl-c">#</span> is implemented by NTuple</span>
a<span class="pl-k">.</span>r <span class="pl-c"><span class="pl-c">#</span> implemented by RGB</span>
<span class="pl-c"><span class="pl-c">#</span>Should not work:</span>
(<span class="pl-c1">1</span>,<span class="pl-c1">2</span>,<span class="pl-c1">3</span>)<span class="pl-k">.</span>r</pre></div>
<p dir="auto">To further dwell on the point, that we can have a diversity of simd accelerated Vector types, with minimal re-implementation of common functionality, here is another example:</p>
<h4 dir="auto">Adding Semantic to generic Types</h4>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="immutable Point{T, N} &lt;: NTuple{N, T}
immutable RGB{T, N} &lt;: NTuple{N, T}

immutable Red{T &lt;: Real} &lt;: T
immutable Green{T &lt;: Real} &lt;: T
immutable Blue{T &lt;: Real} &lt;: T

red = Red(1f0) # -&gt; this will behave exactly like a normal Float32 value 
# making it unnecessary, to re-implement all the operations on it

immutable X{T &lt;: Real} &lt;: T
immutable Y{T &lt;: Real} &lt;: T
immutable Z{T &lt;: Real} &lt;: T

Base.getfield(c::RGB, field::Type{Red}) = Red(c[1])
...
Base.getfield(p::Point, field::Type{X}) = X(p[1])
...
Base.getfield(p::Matrix{RGB}, field::Type{Red}) = ... # -&gt; Matrix{Red}
Base.getfield(p::Matrix{Point}, field::Type{X}) = ... # -&gt; Matrix{X}
...
image = [RGB(1f0, 0f0,0f0) for i=1:512, j=1:512]
points = [Point(1f0, 0f0,0f0) for i=1:512, j=1:512]

redchannel = image.Red
zplane = image.Z"><pre class="notranslate">immutable Point{T, N} <span class="pl-k">&lt;:</span> <span class="pl-c1">NTuple{N, T}</span>
immutable RGB{T, N} <span class="pl-k">&lt;:</span> <span class="pl-c1">NTuple{N, T}</span>

immutable Red{T <span class="pl-k">&lt;:</span> <span class="pl-c1">Real</span>} <span class="pl-k">&lt;:</span> <span class="pl-c1">T</span>
immutable Green{T <span class="pl-k">&lt;:</span> <span class="pl-c1">Real</span>} <span class="pl-k">&lt;:</span> <span class="pl-c1">T</span>
immutable Blue{T <span class="pl-k">&lt;:</span> <span class="pl-c1">Real</span>} <span class="pl-k">&lt;:</span> <span class="pl-c1">T</span>

red <span class="pl-k">=</span> <span class="pl-c1">Red</span>(<span class="pl-c1">1f0</span>) <span class="pl-c"><span class="pl-c">#</span> -&gt; this will behave exactly like a normal Float32 value </span>
<span class="pl-c"><span class="pl-c">#</span> making it unnecessary, to re-implement all the operations on it</span>

immutable X{T <span class="pl-k">&lt;:</span> <span class="pl-c1">Real</span>} <span class="pl-k">&lt;:</span> <span class="pl-c1">T</span>
immutable Y{T <span class="pl-k">&lt;:</span> <span class="pl-c1">Real</span>} <span class="pl-k">&lt;:</span> <span class="pl-c1">T</span>
immutable Z{T <span class="pl-k">&lt;:</span> <span class="pl-c1">Real</span>} <span class="pl-k">&lt;:</span> <span class="pl-c1">T</span>

Base<span class="pl-k">.</span><span class="pl-en">getfield</span>(c<span class="pl-k">::</span><span class="pl-c1">RGB</span>, field<span class="pl-k">::</span><span class="pl-c1">Type{Red}</span>) <span class="pl-k">=</span> <span class="pl-c1">Red</span>(c[<span class="pl-c1">1</span>])
<span class="pl-k">...</span>
Base<span class="pl-k">.</span><span class="pl-en">getfield</span>(p<span class="pl-k">::</span><span class="pl-c1">Point</span>, field<span class="pl-k">::</span><span class="pl-c1">Type{X}</span>) <span class="pl-k">=</span> <span class="pl-c1">X</span>(p[<span class="pl-c1">1</span>])
<span class="pl-k">...</span>
Base<span class="pl-k">.</span><span class="pl-en">getfield</span>(p<span class="pl-k">::</span><span class="pl-c1">Matrix{RGB}</span>, field<span class="pl-k">::</span><span class="pl-c1">Type{Red}</span>) <span class="pl-k">=</span> <span class="pl-k">...</span> <span class="pl-c"><span class="pl-c">#</span> -&gt; Matrix{Red}</span>
Base<span class="pl-k">.</span><span class="pl-en">getfield</span>(p<span class="pl-k">::</span><span class="pl-c1">Matrix{Point}</span>, field<span class="pl-k">::</span><span class="pl-c1">Type{X}</span>) <span class="pl-k">=</span> <span class="pl-k">...</span> <span class="pl-c"><span class="pl-c">#</span> -&gt; Matrix{X}</span>
<span class="pl-k">...</span>
image <span class="pl-k">=</span> [<span class="pl-c1">RGB</span>(<span class="pl-c1">1f0</span>, <span class="pl-c1">0f0</span>,<span class="pl-c1">0f0</span>) <span class="pl-k">for</span> i<span class="pl-k">=</span><span class="pl-c1">1</span><span class="pl-k">:</span><span class="pl-c1">512</span>, j<span class="pl-k">=</span><span class="pl-c1">1</span><span class="pl-k">:</span><span class="pl-c1">512</span>]
points <span class="pl-k">=</span> [<span class="pl-c1">Point</span>(<span class="pl-c1">1f0</span>, <span class="pl-c1">0f0</span>,<span class="pl-c1">0f0</span>) <span class="pl-k">for</span> i<span class="pl-k">=</span><span class="pl-c1">1</span><span class="pl-k">:</span><span class="pl-c1">512</span>, j<span class="pl-k">=</span><span class="pl-c1">1</span><span class="pl-k">:</span><span class="pl-c1">512</span>]

redchannel <span class="pl-k">=</span> image<span class="pl-k">.</span>Red
zplane <span class="pl-k">=</span> image<span class="pl-k">.</span>Z</pre></div>
<h6 dir="auto">Now the big magic, won by more type information</h6>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="visualize(image) #  -&gt; rgb image display
visualize(points) # -&gt; point cloud 
visualize(redchannel) # I can actually infer what the user wants to see: a red intensity image
visualize(zplane) # Again, it's relatively clear what is expected here: a heightfield"><pre class="notranslate"><span class="pl-c1">visualize</span>(image) <span class="pl-c"><span class="pl-c">#</span>  -&gt; rgb image display</span>
<span class="pl-c1">visualize</span>(points) <span class="pl-c"><span class="pl-c">#</span> -&gt; point cloud </span>
<span class="pl-c1">visualize</span>(redchannel) <span class="pl-c"><span class="pl-c">#</span> I can actually infer what the user wants to see: a red intensity image</span>
<span class="pl-c1">visualize</span>(zplane) <span class="pl-c"><span class="pl-c">#</span> Again, it's relatively clear what is expected here: a heightfield</span></pre></div>
<p dir="auto">This would be pretty much the paradise for any visualization library. Also, visual debugging is made a lot easier, as the debugger doesn't need any magic to infer how it needs to visualize some random variable.<br>
But this matters for more than that, as it becomes easier to do the correct thing with any value.<br>
I you want to see something else, for example the pixel of the image in RGB space, you can simply reinterpret the RGB to Point (which has O(1)), which can be useful to make out color clusters.</p>
<h4 dir="auto">Let function bodies only do, what is implied by their function name</h4>
<p dir="auto">Compare these two implementations:</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="#First implementation of matrix multiplication
function (*)(a::Matrix, b::Matrix) 
  @assert size(a, 2) == size(b, 1) #This isn't part of the multiplication code
  #matrix multiplication code
end
# This is probably a matter of taste, but I like this implementation more:
FixedSizeArray{SZ, T, N} &lt;: Array{T,N}
Base.call{T,N}(::Type{FixedSizeArray}, x::Array{T,N}) = FixedSizeArray{size(x), T,N}(x)
function (*)(a::Matrix, b::Matrix) 
 return (FixedSizeArray(a) * FixedSizeArray(b))
end
# Like this, in the function body is only, what is really part of the matrix multiplication:
function (*)(a::FixedMatrix{T, N, M}, b::FixedMatrix{T, M, P})
 # code for multiplication of matrices with well suited dimensions
end
function (*)(a::FixedMatrix, b::FixedMatrix)
# code for multiplication of matrices with arbitrary dimensions
# which usually throws an error
end"><pre class="notranslate"><span class="pl-c"><span class="pl-c">#</span>First implementation of matrix multiplication</span>
<span class="pl-k">function</span> (<span class="pl-k">*</span>)(a<span class="pl-k">::</span><span class="pl-c1">Matrix</span>, b<span class="pl-k">::</span><span class="pl-c1">Matrix</span>) 
  <span class="pl-c1">@assert</span> <span class="pl-c1">size</span>(a, <span class="pl-c1">2</span>) <span class="pl-k">==</span> <span class="pl-c1">size</span>(b, <span class="pl-c1">1</span>) <span class="pl-c"><span class="pl-c">#</span>This isn't part of the multiplication code</span>
  <span class="pl-c"><span class="pl-c">#</span>matrix multiplication code</span>
<span class="pl-k">end</span>
<span class="pl-c"><span class="pl-c">#</span> This is probably a matter of taste, but I like this implementation more:</span>
FixedSizeArray{SZ, T, N} <span class="pl-k">&lt;:</span> <span class="pl-c1">Array{T,N}</span>
Base<span class="pl-k">.</span><span class="pl-en">call</span><span class="pl-c1">{T,N}</span>(<span class="pl-k">::</span><span class="pl-c1">Type{FixedSizeArray}</span>, x<span class="pl-k">::</span><span class="pl-c1">Array{T,N}</span>) <span class="pl-k">=</span> <span class="pl-c1">FixedSizeArray</span><span class="pl-c1">{size(x), T,N}</span>(x)
<span class="pl-k">function</span> (<span class="pl-k">*</span>)(a<span class="pl-k">::</span><span class="pl-c1">Matrix</span>, b<span class="pl-k">::</span><span class="pl-c1">Matrix</span>) 
 <span class="pl-k">return</span> (<span class="pl-c1">FixedSizeArray</span>(a) <span class="pl-k">*</span> <span class="pl-c1">FixedSizeArray</span>(b))
<span class="pl-k">end</span>
<span class="pl-c"><span class="pl-c">#</span> Like this, in the function body is only, what is really part of the matrix multiplication:</span>
<span class="pl-k">function</span> (<span class="pl-k">*</span>)(a<span class="pl-k">::</span><span class="pl-c1">FixedMatrix{T, N, M}</span>, b<span class="pl-k">::</span><span class="pl-c1">FixedMatrix{T, M, P}</span>)
 <span class="pl-c"><span class="pl-c">#</span> code for multiplication of matrices with well suited dimensions</span>
<span class="pl-k">end</span>
<span class="pl-k">function</span> (<span class="pl-k">*</span>)(a<span class="pl-k">::</span><span class="pl-c1">FixedMatrix</span>, b<span class="pl-k">::</span><span class="pl-c1">FixedMatrix</span>)
<span class="pl-c"><span class="pl-c">#</span> code for multiplication of matrices with arbitrary dimensions</span>
<span class="pl-c"><span class="pl-c">#</span> which usually throws an error</span>
<span class="pl-k">end</span></pre></div>
<p dir="auto">This all is mostly graphic related, which isn't a big surprise considering my background. But I'm pretty sure, that there are good use cases for other fields ;)<br>
But I better not iterate more use cases here, as this would turn even more into a novel.</p>
<p dir="auto">Hope we can realize this in some way!</p>
<p dir="auto">Best,<br>
Simon</p>