<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Julia Community 🟣: Matthijs Cox</title>
    <description>The latest articles on Julia Community 🟣 by Matthijs Cox (@matthijscox).</description>
    <link>https://forem.julialang.org/matthijscox</link>
    <image>
      <url>https://forem.julialang.org/images/0UkfUdLs_FIq8QizLeddQz8cjFXHugBTUb2cZwlQuxw/rs:fill:90:90/g:sm/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L3VzZXIvcHJvZmls/ZV9pbWFnZS82NTIv/NGUyZmMyMDktNGY3/OC00YzM4LWE4OTEt/YTkyZDgyMDg5MWY4/LmpwZw</url>
      <title>Julia Community 🟣: Matthijs Cox</title>
      <link>https://forem.julialang.org/matthijscox</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.julialang.org/feed/matthijscox"/>
    <language>en</language>
    <item>
      <title>How to solve the two language problem?</title>
      <dc:creator>Matthijs Cox</dc:creator>
      <pubDate>Mon, 08 May 2023 08:03:46 +0000</pubDate>
      <link>https://forem.julialang.org/matthijscox/how-to-solve-the-two-language-problem-17d1</link>
      <guid>https://forem.julialang.org/matthijscox/how-to-solve-the-two-language-problem-17d1</guid>
      <description>&lt;p&gt;My professional obsession is solving the &lt;a href="https://scientificcoder.com/my-target-audience#heading-the-two-culture-problem"&gt;Two Culture Problem&lt;/a&gt;. How can scientists optimally join forces with software engineers and their principles, so that we can work on the same problems &lt;em&gt;together&lt;/em&gt;? How to accelerate the cycle from idea to product? The Two Culture Problem requires a solution to the related Two Language Problem, which has a technical nature. A solution to the technical problem does not guarantee a solution to the organizational problem, but when it comes to engineering cultures you first need to prove the technical solution before you can even begin to tackle the social implications. I have a strong opinion on the best technical solution, but let's review all our options.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/mSrArrbeJbMpx6iKdKFBqR3BS1jCIZEGNS2dsIOgW-k/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL3U5/enBpNTN0dXZjaHVx/OGhwbjBsLlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/mSrArrbeJbMpx6iKdKFBqR3BS1jCIZEGNS2dsIOgW-k/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL3U5/enBpNTN0dXZjaHVx/OGhwbjBsLlBORw" alt="Two Culture Problem" width="800" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As far as I can tell, we have the following alternatives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Accept the status quo: use a slow and a fast (usually harder) language&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Code generation using a look-a-like framework inside the slow language&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using (LLVM-based) optimization frameworks that look like the slow language&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Speed up the slow language itself, working around its limitations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Design a new language that is both easy and fast&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many tutorials about all of these options. Here I'd like to write a short overview of all of these.&lt;/p&gt;

&lt;p&gt;For another similar technical overview, see Martin Maas's blog posts about &lt;a href="https://www.matecdev.com/posts/julia-python-numba-cython.html"&gt;Julia vs Python vs Numba vs Cython&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two language problem - Python and C++ as a primary example
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/CE0jnXxOWCdo3dApckF8zDUZWne-pUP6SiiEgVr11gE/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzLzMx/b253a2pxdmc2bG03/OHpibm9vLlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/CE0jnXxOWCdo3dApckF8zDUZWne-pUP6SiiEgVr11gE/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzLzMx/b253a2pxdmc2bG03/OHpibm9vLlBORw" alt="Python to Cpp" width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your scientists or domain experts write prototypes in a simple language, let's say Python, where they can rapidly explore, do dynamic data analysis, model desired behavior and gather requirements from users. When they find something valuable, software engineers convert the prototype into high-performant code, let's say C++, and integrate it into production systems to sell as professional services to those users. This is my assumption of the status quo.&lt;/p&gt;

&lt;p&gt;(I will continue to refer to the modeling culture as "scientists" whether or not they are actual scientists, domain experts, requirements engineers, data analysts, quants or any other kind of expert whose primary job is modeling the behavior of your product without actually writing and deploying the final source code.)&lt;/p&gt;

&lt;p&gt;Depending on the size of your organization and the skill level of your engineers, you may end up with several configurations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Teams of highly skilled scientific engineers who can do all the work&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Teams with a mix of scientists and software engineers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Separate teams of scientists and separate teams of software engineers&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may have any combination of the above. The first option is a team of unicorns, which I have seen the least, but is amazing to work with.&lt;/p&gt;

&lt;p&gt;Perhaps you have accepted this status quo. As the organization grows, separate code bases may evolve for the two types of tasks. In my experience, the production code rarely gets re-integrated into the analysis code, because it's not worth the effort in the short term. Long term you may get inconsistencies and other issues, but that's typically for someone else to worry about. Or perhaps people notice the problems, but profit margins are good, so why worry?&lt;/p&gt;

&lt;p&gt;If you integrate your fast code (C++) as embedded libraries into the slow language (Python), you typically need some intermediate glue code or language in between. This requires yet more technical expertise from your people. See for example this blog about &lt;a href="https://www.matecdev.com/posts/cpp-call-from-python.html"&gt;How to Call C++ from Python&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One stated benefit of keeping the two-language culture intact is that your prototypes and your scientists never mess up your production systems. The production systems are brittle and valuable, so this is a valid concern, but I think there are better ways to teach people to write better code than by blocking them.&lt;/p&gt;

&lt;p&gt;For this article, I assume you are looking for alternatives. Maybe the problems have grown too big, or you want to avoid them early on, or you simply cannot hire enough senior software engineers. Thus for one reason or another, you need your scientists to be deeply involved in the software development.&lt;/p&gt;

&lt;p&gt;Learning C/C++ is still a good idea to grow your expertise or the competence of your scientists, but it can take a long time to develop. At a minimum, I advise learning what it means to compile and link libraries. And learn a bit about computers by reading great summaries such as &lt;a href="https://viralinstruction.com/posts/hardware/"&gt;What Scientists Should Know About Hardware to Write Fast Code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Still want to find a technology that's easier to use, yet brings some of the hardcore software benefits? Let's see what's possible!&lt;/p&gt;

&lt;h2&gt;
  
  
  Code generation - Cython example
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/SaJYcWFGC0aU0egsEbmsVRI8ICcW8tga0fvz3a9FmVY/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzLzk1/YWV3M2Z5amJmYzNn/MTlkMGV2LlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/SaJYcWFGC0aU0egsEbmsVRI8ICcW8tga0fvz3a9FmVY/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzLzk1/YWV3M2Z5amJmYzNn/MTlkMGV2LlBORw" alt="Cython" width="800" height="231"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Generating low-level code, most likely C, from a high-level language, most likely Python, is typically done to try to avoid some of the disadvantages of the two-language problem. Maybe you want to compile static libraries to embed into devices. Or you have some other reason. Unless your examples are very simple, do not expect big performance boosts though, the generated code still needs to make similar kinds of assumptions as the high-level language. Also, most code generators do not support the complete language semantics, so you will have to make sure your high-level code adheres to the capabilities of the generator.&lt;/p&gt;

&lt;p&gt;In Python you can use the &lt;a href="https://cython.readthedocs.io/en/latest/"&gt;Cython&lt;/a&gt; 'compiler' to help you generate C code. On the surface it looks a lot like Python, yet with C types and certain decorators. This means you need to rewrite the parts of your codebase that you want to speed up. The process of turning Python into Cython is sometimes called "cythonizing". You get such examples in the &lt;a href="https://cython.readthedocs.io/en/latest/src/quickstart/cythonize.html"&gt;Cython quickstart tutorial&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;cython&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cfunc&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;cython&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exceptval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cython&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cython&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;integrate_f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cython&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cython&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cython&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cython&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cython&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;double&lt;/span&gt;
    &lt;span class="n"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cython&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;double&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;dx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;dx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have to &lt;a href="https://cython.readthedocs.io/en/latest/src/quickstart/build.html"&gt;build this cythonized code&lt;/a&gt;. As I mentioned, this happens in two stages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;.py&lt;/code&gt; or &lt;code&gt;.pyx&lt;/code&gt; file is converted by Cython to a &lt;code&gt;.c&lt;/code&gt; file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;.c&lt;/code&gt; file is compiled by a C compiler to a &lt;code&gt;.so&lt;/code&gt; file (or &lt;code&gt;.pyd&lt;/code&gt; on Windows) which can be &lt;code&gt;import&lt;/code&gt;-ed back into Python with &lt;a href="https://setuptools.pypa.io/en/latest/"&gt;setuptools&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The downside of Cython, and any similar C code generator, is that you obtain rather obscure C code. If you want code obfuscation, you can consider that a benefit, but trouble begins when you have to work with that C code. It can be hard to debug once deployed in the field. Make sure to add lots of clear error messages and logging. If you integrate the generated code inside existing C/C++ codebases, your software engineers may dislike writing the necessary glue-code (I learned that from experience). Finally, naive Cython is not very performant and writing &lt;a href="https://notes-on-cython.readthedocs.io/en/latest/std_dev.html"&gt;optimized Cython&lt;/a&gt; can be as difficult as writing regular C code. But the benefit is that you can move gradually up in complexity.&lt;/p&gt;

&lt;p&gt;How to make a standalone-ish distribution? Cython generates code that interfaces with the python runtime. You can create a binary executable, but you also need to distribute it with &lt;a href="http://libpython.so/dll"&gt;&lt;code&gt;libpython.so&lt;/code&gt;&lt;/a&gt; which is the python runtime. Moreover, you also need to add all the python dependencies and .so/.dlls that those packages are using. This might be a bit tedious using Cython, but it is certainly possible. Other packages like Nuitka make this process a bit less painless by figuring out all your dependencies.&lt;/p&gt;

&lt;p&gt;Fun fact: Code generation is sometimes referred to as "transpiling", since you &lt;em&gt;translate&lt;/em&gt; your code to another language that's ready for &lt;em&gt;compiling&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interlude: LLVM
&lt;/h2&gt;

&lt;p&gt;What if we do not want to write or generate C code? Do we have any other options? Yes, we can generate something else: LLVM code! Before we go into such frameworks, let's do a quick introduction into LLVM itself.&lt;/p&gt;

&lt;p&gt;LLVM is a middleman between your source code and the compiled native code. Compilers typically consist of two stages: byte code and native code. The byte code is an intermediate representation that is agnostic of the CPU or GPU architecture. LLVM is an attempt to standardize the byte code definition, which will then be compiled for you to any architecture you want. In some frameworks or languages (like Julia) you can ask to see the LLVM code, and the eventual native code, the processor instructions, which is typically assembly code (that's just before it becomes those zeros and ones you always hear about).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/ymJDsjUAHKWLs6Nrr3jroyJ-3T2QZVsVxIYxI8OgeuU/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL3R2/ZzZyaXpsNWxudXBs/N3M5Nm5hLlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/ymJDsjUAHKWLs6Nrr3jroyJ-3T2QZVsVxIYxI8OgeuU/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL3R2/ZzZyaXpsNWxudXBs/N3M5Nm5hLlBORw" alt="LLVM explanation" width="800" height="361"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Frameworks that use LLVM may store the compiled native code in memory. In that case, if you want to distribute the compiled code, you need the option to package the native code into a library (that's a .so on Linux or a .dll on Windows) together with all of its dependencies. This packaging option may be important to investigate for your deployment strategy.&lt;/p&gt;

&lt;p&gt;Fun fact: the &lt;a href="https://clang.llvm.org/"&gt;clang&lt;/a&gt; compiler from C also compiles via LLVM. So if you write Cython and then compile via clang, you are taking an interesting route.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimization Frameworks - Numba example
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/w2TaFzQAr4jKgD5IuD2HXVFJf5JqfySO65t2HbsGJy8/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2Rm/ZTYxNXpvMGV3cGZ6/ZTVjNGtyLlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/w2TaFzQAr4jKgD5IuD2HXVFJf5JqfySO65t2HbsGJy8/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2Rm/ZTYxNXpvMGV3cGZ6/ZTVjNGtyLlBORw" alt="Numba to LLVM" width="800" height="243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://numba.pydata.org/"&gt;Numba&lt;/a&gt; is an LLVM code generator that integrates directly with Python. What you need to do is add decorators to every Python function you want to optimize. In principle it looks simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;jit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;nopython&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JIT stands for Just-In-Time, as it compiles to LLVM at the moment of calling the function, and inferring which types you used, just in time before executing. You can optionally provide the types yourself, as I did above. And there are lots of other settings for the &lt;code&gt;@jit&lt;/code&gt; decorator, like the &lt;a href="https://numba.readthedocs.io/en/stable/glossary.html#term-nopython-mode"&gt;nopython mode&lt;/a&gt; to get faster performance.&lt;/p&gt;

&lt;p&gt;Only a subset of Python is supported with Numba. It works well with your NumPy code, they made sure of that. It doesn't work with other packages such as Pandas, because those work differently. Even dictionaries are not supported by Numba. Nobody writes a custom file format parser in Numba, it's purely for numerical code.&lt;/p&gt;

&lt;p&gt;If you want to compile to GPU: there are other decorators, such as &lt;code&gt;cuda.@jit&lt;/code&gt;. This suggests you need to edit your code for GPU.&lt;/p&gt;

&lt;p&gt;If you want to compile ahead of time, you will again have to replace all your &lt;code&gt;@jit&lt;/code&gt; decorators with the &lt;code&gt;@cc.export&lt;/code&gt; decorator and be explicit about your types.&lt;/p&gt;

&lt;p&gt;You cannot debug the jitted Numba code itself, you'll have to change the decorator setting to &lt;a href="https://numba.readthedocs.io/en/stable/user/troubleshoot.html#debugging-jit-compiled-code"&gt;debug mode&lt;/a&gt; and use the gdb tool, so be careful there. That's another disadvantage of Numba.&lt;/p&gt;

&lt;p&gt;We have never tried to make a standalone distribution of Numba compiled code, but I assume you ship the entire Python environment, with the ahead-of-time compiled code. If someone has experience with the nitty-gritty details of distributing Numba code, then let me know!&lt;/p&gt;

&lt;h3&gt;
  
  
  Codon
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/exaloop/codon"&gt;Codon&lt;/a&gt; is a recent attempt similar to Numba, except it claims zero-overhead; you do not necessarily have to decorate your code. Well, except if you want to use it inside larger Python codebases (you probably do), then you have the &lt;code&gt;@codon.jit&lt;/code&gt; decorator and other decorators depending on your use-case.&lt;/p&gt;

&lt;p&gt;Codon has only 9 contributors at the moment, and it has a non-permissive license, so you'll have to pay to use Codon commercially in production. It's interesting but looks more like a startup than a regular open-source project. Similar to Numba it only supports a subset of the Python language, which may get better over time (or worse, if Python evolves, yet the developers do not update Codon).&lt;/p&gt;

&lt;h3&gt;
  
  
  Jax, TensorFlow, PyTorch
&lt;/h3&gt;

&lt;p&gt;Every scientific computing and machine learning framework in Python implements its own optimized numerical libraries it seems. Some of them, like &lt;a href="https://jax.readthedocs.io/en/latest/notebooks/quickstart.html#using-jit-to-speed-up-functions"&gt;JAX&lt;/a&gt;, have a &lt;code&gt;@jit&lt;/code&gt; decorator like Numba. All these frameworks look like Python, but to get performant code you'll have to use their API, not Python itself. Often you write Python in a more complicated directed-acyclic-graph (DAG) structure that can be fed to the underlying libraries for execution. Don't ask me how to debug these things. Please consider whether you are really writing Python or another language.&lt;/p&gt;

&lt;p&gt;Also see this section from the Mojo language comparing such &lt;a href="https://docs.modular.com/mojo/why-mojo.html#related-work-other-approaches-to-improve-python"&gt;Python improvements&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Boost the slow language - PyPy
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/2cwKmGQ6EWov9WCtdhDtElM4MpzNu4SEJO6U0ZXEQus/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2lx/NnJwdXJ5d2R3N2sz/YzlzMXkzLlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/2cwKmGQ6EWov9WCtdhDtElM4MpzNu4SEJO6U0ZXEQus/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2lx/NnJwdXJ5d2R3N2sz/YzlzMXkzLlBORw" alt="Boost Python" width="800" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a continuous effort to improve the performance of slow interpreted languages like Python and R. In a blog post called &lt;a href="https://towardsdatascience.com/python-3-14-will-be-faster-than-c-a97edd01d65d"&gt;Python 3.14 Will be Faster than C++&lt;/a&gt; the author joked that linear extrapolation of Python improvements will soon surpass C++ performance. Let's see how that graph evolves in the next Python versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  PyPy
&lt;/h3&gt;

&lt;p&gt;An alternative to waiting for Python to improve is &lt;a href="https://www.pypy.org/features.html"&gt;PyPy&lt;/a&gt;. This is a replacement for CPython. Note, CPython is not Cython. &lt;a href="https://github.com/python/cpython"&gt;CPython&lt;/a&gt; is essentially Python itself, as the Python interpreter is written in the C language. PyPy is an attempt to make the entire Python language faster with a better interpreter. PyPy can optionally use LLVM as a backend, to use similar tricks as Numba, and also has a JIT decorator.&lt;/p&gt;

&lt;p&gt;In general, the Python language design creates limitations on the performance, see this video for example on &lt;a href="https://www.youtube.com/watch?v=qCGofLIzX6g"&gt;How Python was Shaped by Leaky Internals&lt;/a&gt;. If you don't want to change language, you may hope that Python 4 ever comes around with syntax that can actually be optimized.&lt;/p&gt;

&lt;h2&gt;
  
  
  An optimized language - Julia as example
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/Zh2nKcM0IXJlycRlsQlWoHDKDu70O5JOzjvpqszkjM0/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL3dk/NHhsYTVpenU0YXhr/OGJ0djU5LlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/Zh2nKcM0IXJlycRlsQlWoHDKDu70O5JOzjvpqszkjM0/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL3dk/NHhsYTVpenU0YXhr/OGJ0djU5LlBORw" alt="Julia to LLVM" width="800" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don't want to wait for Python 4, then there's &lt;a href="https://julialang.org/"&gt;Julia&lt;/a&gt; instead. Julia is a language that is optimized for talking to LLVM, while looking as similar as possible to high-level languages like Python and MATLAB. In short, it's an LLVM whisperer. This makes it fast and easy. See &lt;a href="https://julialang.org/blog/2012/02/why-we-created-julia/"&gt;Why Was Julia created?&lt;/a&gt; to get an impression of the rationale.&lt;/p&gt;

&lt;p&gt;Similar to Cython and Numba, you can optionally add type information to Julia, which can help the compiler, though Julia is good at type interference.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Is Julia better than Numba and Cython? For an opinionated and long blog post read &lt;a href="https://www.stochasticlifestyle.com/why-numba-and-cython-are-not-substitutes-for-julia/"&gt;Why Numba and Cython are not substitutes for Julia&lt;/a&gt;. There are also lengthy discussions in this discourse on &lt;a href="https://discourse.julialang.org/t/julia-motivation-why-werent-numpy-scipy-numba-good-enough/"&gt;Why weren't Numpy, Numba, SciPy good enough?&lt;/a&gt;. And I also like Martin Maas's blog post about &lt;a href="https://www.matecdev.com/posts/julia-python-numba-cython.html"&gt;Julia vs Numba and Cython&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I would summarize the benefits as: You don't have to decorate your code, Julia &lt;em&gt;is&lt;/em&gt; the JIT decorator. You can write the same code for CPU and GPU. When compiling ahead-of-time, it's again the same code. The compiler can optimize across all Julia code, not just a single package like NumPy that you are currently using. Composability is often praised: Julia packages work easily together.&lt;/p&gt;

&lt;p&gt;The downside of Julia, if you are coming from another language like Python, is obviously that you have to learn another language. Though I wonder how much more difficult Julia is compared to learning a complex framework like Numba. And writing optimized Cython can be considered similar to writing another language. Julia has many similarities with Python, check for example this &lt;a href="https://cheatsheets.quantecon.org/"&gt;cheat sheet to compare MATLAB to Python to Julia&lt;/a&gt;, except Julia bypasses the problems that make Python difficult to compile to LLVM.&lt;/p&gt;

&lt;p&gt;Similar to Cython and Numba, naive Julia code is good, but not necessarily as performant as optimized C. Read the &lt;a href="https://docs.julialang.org/en/v1/manual/performance-tips/"&gt;performance tips&lt;/a&gt; to get the most out of your code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/xfhmrhGPQiNpkvNlxYQMxjn5FCupxzxlOVSQa2U4LZE/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzLzJt/cGhheDh4aGMxc3cx/N2JlYm01LlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/xfhmrhGPQiNpkvNlxYQMxjn5FCupxzxlOVSQa2U4LZE/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzLzJt/cGhheDh4aGMxc3cx/N2JlYm01LlBORw" alt="PythonCall" width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to move gradually to Julia, you can embed Julia into Python via &lt;a href="https://github.com/JuliaPy/pyjulia"&gt;PyJulia&lt;/a&gt; or the more recent two-way package &lt;a href="https://github.com/cjdoris/PythonCall.jl"&gt;PythonCall&lt;/a&gt;. Or you can re-use existing Python code inside Julia, via &lt;a href="https://github.com/JuliaPy/PyCall.jl"&gt;PyCall.jl&lt;/a&gt;, or the aforementioned PythonCall. This way you can use Julia as if it's yet another Python framework, instead of a completely new language. You can even send &lt;a href="https://cjdoris.github.io/PythonCall.jl/stable/compat/#Tabular-data-/-Pandas"&gt;Pandas dataframes&lt;/a&gt; to Julia and back.&lt;/p&gt;

&lt;p&gt;Similar to Numba, Julia stores the compiled native code in memory. In the upcoming Julia 1.9 release, this code will also be automatically cached on disk per Julia package, so compilation happens only once, instead of the first call in every new Julia session. Ahead-of-time compilation was always possible with &lt;a href="https://github.com/JuliaLang/PackageCompiler.jl"&gt;PackageCompiler.jl&lt;/a&gt;. The PackageCompiler is not actually compiling (Julia and LLVM do that), it simply gathers the in-memory compiled code and stores it in a &lt;code&gt;.so&lt;/code&gt; library (or &lt;code&gt;.dll&lt;/code&gt; on windows). This can be used for a standalone library of your compiled code, and will automatically include all dependent libraries. I have written a long tutorial on how to &lt;a href="https://www.functionalnoise.com/pages/2022-07-21-embedding/"&gt;embed such Julia libraries inside C++&lt;/a&gt; on my private website.&lt;/p&gt;

&lt;p&gt;Static compilation of Julia, into tiny libraries fully independent of the runtime, is in an early stage with &lt;a href="https://github.com/tshort/StaticCompiler.jl"&gt;StaticCompiler.jl&lt;/a&gt; and &lt;a href="https://github.com/brenhinkeller/StaticTools.jl"&gt;StaticTools.jl&lt;/a&gt;, but needs more investment. Once you try out static compilation, you will notice that it enforces limitations on your code, because you cannot use all the fancy dynamic language features. I believe this is an unavoidable trade-off in any of the discussed technologies so far, but I'd love to be surprised on this point.&lt;/p&gt;

&lt;p&gt;Other attempts to make a fast language easier to use are Zig, Swift and GoLang to a certain extent. Rust is very interesting, but I would not call it easy for scientists. None of them are targeting numerical computing as much as Julia.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mojo
&lt;/h3&gt;

&lt;p&gt;A new language that was revealed very recently is Mojo. In their article &lt;a href="https://docs.modular.com/mojo/why-mojo.html"&gt;Why Mojo?&lt;/a&gt; they rephrase the two language problem as a Two World Problem, or even three world problem (Python, C++ and CUDA) for machine learning. From the code snippets on their website it looks like they want a Python compatible language that has features of Rust. Note that Mojo is not yet released to the public, the &lt;a href="https://github.com/modularml/mojo"&gt;mojo github repository&lt;/a&gt; is empty at this time of writing, so we don't even know if Mojo will have a permissive license. Ambitious, but very young. We'll keep an eye on this one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Comparison
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/Zsmd2tYQ16jBGX5hshnmrueljoYThMBqR__r30rHteE/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzLzMx/NmdraXQ3ODVpMmM2/aXZjbm42LlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/Zsmd2tYQ16jBGX5hshnmrueljoYThMBqR__r30rHteE/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzLzMx/NmdraXQ3ODVpMmM2/aXZjbm42LlBORw" alt="Comparison" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What are good comparison criteria? I have chosen a few below. The development community size can be used as an estimate of how much effort goes into each project. Other than that I have tried to compare the usage and technology choices. I don't want to give quantitative performance comparisons here, they are heavily dependent on your use case, but from the benchmarks on complex examples that I have seen, Julia typically performs best. However, performance might not be your main criterion. Other unlisted aspects, such as debugging, profiling or cloud deployment may be more relevant for your use case.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Cython&lt;/th&gt;
&lt;th&gt;Numba&lt;/th&gt;
&lt;th&gt;Julia&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Contributors&lt;/td&gt;
&lt;td&gt;430&lt;/td&gt;
&lt;td&gt;298&lt;/td&gt;
&lt;td&gt;1386&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Github stars&lt;/td&gt;
&lt;td&gt;7.9k&lt;/td&gt;
&lt;td&gt;8.6k&lt;/td&gt;
&lt;td&gt;42.2k&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend tech&lt;/td&gt;
&lt;td&gt;C transpiler&lt;/td&gt;
&lt;td&gt;LLVM&lt;/td&gt;
&lt;td&gt;LLVM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Usage&lt;/td&gt;
&lt;td&gt;Decorators and Cython types&lt;/td&gt;
&lt;td&gt;Decorators everywhere&lt;/td&gt;
&lt;td&gt;Learn another language&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python interoperability&lt;/td&gt;
&lt;td&gt;Import cythonized modules&lt;/td&gt;
&lt;td&gt;Just-in-Time (JIT) decorators&lt;/td&gt;
&lt;td&gt;PythonCall package&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;td&gt;Decent&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Best&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Distribution&lt;/td&gt;
&lt;td&gt;Ship the .so with all dependencies&lt;/td&gt;
&lt;td&gt;Ahead-of-Time compilation decorators&lt;/td&gt;
&lt;td&gt;Ahead-of-Time compilation via PackageCompiler.jl&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;While I have a preference for Julia, I tried to stay as unbiased as possible in this blog post. All options are amazing open source projects and are maintained by mostly voluntary developer communities. Investigating them all is a humbling experience in the complexity of software technology.&lt;/p&gt;

&lt;p&gt;There are other software engineering requirements that I have not yet included in this post, but might be important for your use case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Package management. How easy is it to create and install a package, with all of its dependencies, in the chosen technology. I believe Julia's &lt;a href="https://pkgdocs.julialang.org/v1/"&gt;Pkg&lt;/a&gt; is superior here.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How does dependency management and distribution of binary artifacts work exactly? These nitty-gritty details can slow down your project. I have not yet tried this extensively for Numba. Cython involves some manual work. Julia has an artifact manager that works together with the package manager inside PackageCompiler.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Complex cases, like multi-threading inside the framework or external threads calling from another language. (Note: Julia doesn't have the global interpreter lock (GIL) like Python. Cython can release the GIL in certain cases.) I haven't gone into such topics yet, but there are many complex use cases that you may want to gradually add to your codebase. How far can you go with each technology before hitting a wall?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, remember that a technical solution does not necessarily result in a cultural improvement. If you hired a lot of scientists or analysts or domain experts, and none of them have the necessary software skillset, it is difficult to improve collaboration with software engineers by forcing a 'better' technology onto them. You will have to empower your scientists to learn the necessary software development tools and processes, such as version control, test-driven development and continuous integration. Vice versa, your software engineers can learn the business domain and the tricks of numerical computing with the help of your scientists, to know exactly what code to write. By bridging these gaps, you can create a more effective team that can leverage the full potential of the technology investments you make.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to Jorge Vieyra and Jeroen van der Meer for reviewing and suggesting excellent improvements to the article.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;These long posts take me quite some time and effort to write. If you like them, please encourage me by &lt;a href="https://scientificcoder.com/how-to-solve-the-two-language-problem"&gt;leaving a comment&lt;/a&gt; with suggestions or subscribe to my &lt;a href="https://scientificcoder.com/newsletter"&gt;email newsletter&lt;/a&gt;. With enough support, I intend to write a book about building and deploying professional numerical computing applications. With Julia examples.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>julia</category>
      <category>cpp</category>
      <category>python</category>
      <category>software</category>
    </item>
    <item>
      <title>Automate your Code Quality in Julia</title>
      <dc:creator>Matthijs Cox</dc:creator>
      <pubDate>Fri, 05 May 2023 14:21:25 +0000</pubDate>
      <link>https://forem.julialang.org/matthijscox/automate-your-code-quality-in-julia-12hn</link>
      <guid>https://forem.julialang.org/matthijscox/automate-your-code-quality-in-julia-12hn</guid>
      <description>&lt;p&gt;Code quality is a topic in Julia that I believe deserves more attention from both users and developers. The Julia language originated in academia and focused heavily on helping scientists write better code, which is going great and deserves much praise! However, to onboard more software engineers and professional organizations we're going to have to invest even further into code quality and automated code quality tools and other methods such as used in the field of "quality assurance". In this article I'll explore the current state in the Julia ecosystem.&lt;/p&gt;

&lt;p&gt;At our workplace we have investigated the following tools and practices. I'll start from generic practices and then move on to more advanced tools.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Package structure&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unit testing with Pkg.jl&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automated testing and Continuous Integration (CI)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Code Coverage with Pkg.jl&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Documentation testing with Documenter.jl&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Style guides and JuliaFormatter.jl&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Static Code Analysis with StaticLint.jl&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quality Assurance with Aqua.jl&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Type stability with JET.jl&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's have a look at all of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Packages
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/FdP5OVd1IFwGt65f8v6g6H5xZm1GBjri_Wn2yOHCLSk/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2V1/OXZnZzJ6NTNncXM4/NTMzMWY1LnBuZw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/FdP5OVd1IFwGt65f8v6g6H5xZm1GBjri_Wn2yOHCLSk/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2V1/OXZnZzJ6NTNncXM4/NTMzMWY1LnBuZw" alt="Pkg" width="800" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Julia community uses a standardized package structure and has a single package manager called &lt;a href="https://pkgdocs.julialang.org/v1/"&gt;Pkg.jl&lt;/a&gt;. There's also a single documentation system and a single testing system. This consensus alone helps tremendously with automating any workflows in your projects and organizations.&lt;/p&gt;

&lt;p&gt;Please make sure you share professional code with others via packages. It's straightforward to adhere to the package structure. To get you started with creating well-defined (open source) packages, you can look at &lt;a href="https://github.com/JuliaCI/PkgTemplates.jl"&gt;PkgTemplates.jl&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When setting up my first open source Julia package, I enjoyed the documentation of the &lt;a href="https://bjack205.github.io/JuliaTemplateRepo.jl/dev/index.html"&gt;JuliaTemplateRepo.jl&lt;/a&gt;, which goes through all the basic steps and configurations for a Julia package.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unit Testing
&lt;/h2&gt;

&lt;p&gt;Nowadays unit testing is a common practice in professional software engineering. Developers in Julia should be no exception. Fortunately, according to &lt;a href="https://viralinstruction.com/posts/goodjulia/#strong_ecosystem_tooling_consensus"&gt;Viral Instruction&lt;/a&gt;, 89% of all open source Julia packages have tests, including a lot of beginner packages. It's safe to say that the Julia community puts a lot of emphasis on testing, which I think is remarkable for a language that originated in academia. This really sets a good example.&lt;/p&gt;

&lt;p&gt;All unit testing use the &lt;a href="https://docs.julialang.org/en/v1/stdlib/Test/"&gt;Test.jl&lt;/a&gt; package, which is shipped with the base language. There are some extensions like &lt;a href="https://github.com/ssfrr/TestSetExtensions.jl"&gt;TestSetExtensions.jl&lt;/a&gt; and &lt;a href="https://github.com/JuliaTesting/ReTest.jl"&gt;ReTest.jl&lt;/a&gt;, but I believe you can do most of your work with Test.jl.&lt;/p&gt;

&lt;p&gt;Getting started with testing is trivial in Julia, just add a &lt;code&gt;test/runtests.jl&lt;/code&gt; file to your package and add code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="n"&gt;MyPackage&lt;/span&gt;

&lt;span class="nd"&gt;@testset&lt;/span&gt; &lt;span class="s"&gt;"MyPackage tests"&lt;/span&gt; &lt;span class="k"&gt;begin&lt;/span&gt;
    &lt;span class="nd"&gt;@test&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then run the tests with &lt;code&gt;Pkg.test("MyPackage")&lt;/code&gt; which starts an isolated sandbox environment for the tests.&lt;/p&gt;

&lt;p&gt;If you are creating a reproducible package for others, including your future self, then there is absolutely no reason to not write tests. However, writing good descriptive tests that cover all your bases is a more advanced art. Many books are written on this topic. I would advise to just get started and improve your testing strategy as you grow your codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated Testing &amp;amp; Continuous Integration
&lt;/h2&gt;

&lt;p&gt;Once you have unit tests defined, this aspect is a low hanging fruit for automation. It's very easy to forget to run the unit tests before committing. Automatically testing the code will save you from simple mistakes.&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://bjack205.github.io/JuliaTemplateRepo.jl/dev/CI.html"&gt;setup Github Actions&lt;/a&gt; or use a tool like Jenkins, to automatically run the tests upon every commit and block developers from merging if the unit tests do not pass. &lt;a href="https://github.com/JuliaCI/PkgTemplates.jl"&gt;PkgTemplates.jl&lt;/a&gt; will typically already generate this Github Action for your open source package.&lt;/p&gt;

&lt;p&gt;The tools and practice of frequently and automatically checking your code development is called Continuous Integration (CI). Inside software organization this is often combined with Continuous Deployment (CI/CD). All continuous integration (CI) tools that the Julia community uses can be found in &lt;a href="https://github.com/JuliaCI"&gt;JuliaCI · GitHub&lt;/a&gt;, I will address a few of those. If you want to configure your own Github actions you be inspired by the examples in &lt;a href="https://github.com/julia-actions"&gt;Julia Actions · GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Coverage
&lt;/h2&gt;

&lt;p&gt;A straightforward metric for monitoring your code quality is to check the fraction of code covered by your tests. Similar to automating your tests, this is a very low hanging fruit in the Julia community.&lt;/p&gt;

&lt;p&gt;The code coverage generation itself is embedded inside the package manager via &lt;code&gt;Pkg.test("MyPackage", coverage=true)&lt;/code&gt; . This will generate &lt;code&gt;.jl.cov&lt;/code&gt; files with information about how often a line of code is touched by the tests.&lt;/p&gt;

&lt;p&gt;Analyzing the code coverage visually line-by-line, for example inside VS Code, can help you identify where you are lacking tests, or help you find out where you can delete un-used code that is never called by your functions. You can automatically send the files to a service, like &lt;a href="http://Coveralls.io"&gt;Coveralls.io&lt;/a&gt; or &lt;a href="http://Codecov.io"&gt;Codecov.io&lt;/a&gt;, and analyze in the browser. Here's an example in &lt;a href="https://app.codecov.io/gh/FluxML/Flux.jl/blob/master/src/losses/functions.jl#L155"&gt;Flux's functions.jl file&lt;/a&gt;, that's has one uncovered line (note that it's very common to forget to test our errors or other corner cases):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/lkKoFrS2BY-5F166guT13gQ_ga4toJlpFNK3VEgLS2Y/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL21l/MnZzdXB1MDJtbW8z/MHlzMXl3LlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/lkKoFrS2BY-5F166guT13gQ_ga4toJlpFNK3VEgLS2Y/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL21l/MnZzdXB1MDJtbW8z/MHlzMXl3LlBORw" alt="Codecov" width="770" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can calculate statistics on these coverage files, for example with &lt;a href="https://github.com/JuliaCI/Coverage.jl"&gt;Coverage.jl&lt;/a&gt; or with one of the services above. That way you can monitor coverage statistics over time. And if you use such a service for your open source package you can add a shiny badge to your readme to show-off your coverage.&lt;/p&gt;

&lt;p&gt;Other commercial tools are busy adopting Julia's code coverage, check with your preferred supplier if they already support Julia. If not, please request them to do so.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation Testing
&lt;/h2&gt;

&lt;p&gt;Good documentation is incredible important for the users of your package, both in the open source community as well as inside organizations. Unfortunately, documentation that includes code examples can run out of sync with your code if you forget to test those. But it's very easy to automatically test those code examples with &lt;a href="https://documenter.juliadocs.org/stable/man/doctests/index.html"&gt;Documenter.jl doctesting&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Whenever you write a docstring or write code snippets in your docs folder, just add &lt;code&gt;jldoctest&lt;/code&gt; and the expected output. (I replaced the triple ticks with double ticks, don't know how to properly format that here on Forem.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="sb"&gt;``&lt;/span&gt;&lt;span class="n"&gt;jldoctest&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;

&lt;span class="c"&gt;# output&lt;/span&gt;

&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="sb"&gt;``&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now just add &lt;code&gt;Documenter.doctest(MyPackage)&lt;/code&gt; to your automated tests, and you know immediately when your examples no longer work. Easy!&lt;/p&gt;

&lt;h2&gt;
  
  
  Style Guides &amp;amp; Code Formatting
&lt;/h2&gt;

&lt;p&gt;One of the challenges when working with many people on a single codebase is to adhere to a consistent coding style that is pleasant and unambiguous for everyone. This is where style guides help, together with formatting tools that make it easy to adhere to such a style guide.&lt;/p&gt;

&lt;p&gt;The primary open source Julia style guides are at the moment are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/jrevels/YASGuide"&gt;YAS&lt;/a&gt; (yet another style)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/invenia/BlueStyle"&gt;Blue&lt;/a&gt; style&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/SciML/SciMLStyle"&gt;SciML&lt;/a&gt; style&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can &lt;a href="https://www.julia-vscode.org/docs/stable/userguide/formatter/"&gt;automatically format&lt;/a&gt; your Julia files in VS Code with the click of a button. If you are a command line user, or want to automate the formatting in your CI, you can use the underlying &lt;a href="https://github.com/domluna/JuliaFormatter.jl"&gt;JuliaFormatter.jl&lt;/a&gt; package.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/ml2Nzud98y2Y1M20s9v35o1pLLeuk0GIcE1OdoTBq_M/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzLzlm/OWxmazhhNHc5MDZv/NnR1d3J1LlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/ml2Nzud98y2Y1M20s9v35o1pLLeuk0GIcE1OdoTBq_M/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzLzlm/OWxmazhhNHc5MDZv/NnR1d3J1LlBORw" alt="VSCode formatting" width="613" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This should get you started with code formatting in no time. Discuss with your colleagues which style guide you prefer. Personally I use the &lt;a href="https://github.com/invenia/BlueStyle"&gt;BlueStyle&lt;/a&gt; so far, but the SciML style is relatively new, so looking into that one as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Code Analysis
&lt;/h2&gt;

&lt;p&gt;Static code analysis will look at the code without executing it. One package we found is &lt;a href="https://github.com/julia-vscode/StaticLint.jl"&gt;StaticLint.jl&lt;/a&gt;, which is used primarily by the Julia VS Code plugin &lt;a href="https://github.com/julia-vscode/LanguageServer.jl"&gt;LanguageServer.jl&lt;/a&gt; to report on potential problems in your code. These are normally reported under the "Problems" tab. Here I found a few potential problems inside the &lt;a href="https://github.com/JuliaData/DataFrames.jl"&gt;DataFrames.jl&lt;/a&gt; package:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/WN_XzKHq3ST9WqQRCr6eIQ0zG1R9NyjLIYPJ8N4yoO0/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL3Fy/N2lneWliNDlwNDE5/MWp6ejA5LlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/WN_XzKHq3ST9WqQRCr6eIQ0zG1R9NyjLIYPJ8N4yoO0/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL3Fy/N2lneWliNDlwNDE5/MWp6ejA5LlBORw" alt="VSCode problems" width="760" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The VS Code plugin also reports on potential problems when hovering over code, such as a warning about this unused function argument. These are not reported in the "Problems" tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/pTUjjUXvT5ax13AGDnMCXDCel76kYNsYSlqRTRDgd8w/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2Uw/ODF3bTF1c3pjNWcx/bDFrcmpkLlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/pTUjjUXvT5ax13AGDnMCXDCel76kYNsYSlqRTRDgd8w/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2Uw/ODF3bTF1c3pjNWcx/bDFrcmpkLlBORw" alt="VSCode highlights" width="690" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;StaticLint still misses some documentation for users, but you can use the following &lt;a href="https://gist.github.com/pfitzseb/22493b0214276d3b65833232aa94bf11"&gt;script&lt;/a&gt; and read my discussion in an &lt;a href="https://github.com/julia-vscode/StaticLint.jl/issues/14"&gt;issue here&lt;/a&gt;. After some fiddling with the code and environments I am able to obtain the same "diagnostics" on my REPL for a given file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="x"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;Document&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;:///&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;matcox&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Documents&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Julia&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;static_lint&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;abstractdataframe&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;selection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jl&lt;/span&gt;

&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="x"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;diagnostics&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="x"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;LanguageServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Diagnostic&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LanguageServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Range&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LanguageServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;223&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="x"&gt;),&lt;/span&gt; &lt;span class="n"&gt;LanguageServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Position&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;223&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="x"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"UnusedFunctionArgument"&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;missing&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Julia"&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"An argument is included in a function signature but 
not used within its body."&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="x"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;missing&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So StaticLint.jl can be used, but it's not yet user friendly for integration into any command line interfaces or automated tooling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quality Assurance with Aqua.jl
&lt;/h2&gt;

&lt;p&gt;The package &lt;a href="https://github.com/JuliaTesting/Aqua.jl"&gt;Aqua.jl&lt;/a&gt; is developed to automate quality assurance for Julia. The readme is clear on what it checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;There are no method ambiguities.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are no undefined &lt;code&gt;export&lt;/code&gt;s.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are no unbound type parameters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are no stale dependencies listed in &lt;code&gt;Project.toml&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check that test target of the root project &lt;code&gt;Project.toml&lt;/code&gt; and test project (&lt;code&gt;test/Project.toml&lt;/code&gt;) are consistent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check that all external packages listed in &lt;code&gt;deps&lt;/code&gt; have corresponding &lt;code&gt;compat&lt;/code&gt; entry.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Project.toml&lt;/code&gt; formatting is compatible with Pkg.jl output.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are no "obvious" type piracies&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Aqua provides a function to use in your testing environment, which will report issues and throws an error so your tests cannot pass unless all Aqua checks pass. Here's a snippet of what we get for DataFrames:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="n"&gt;Aqua&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DataFrames&lt;/span&gt;

&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Aqua&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test_all&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DataFrames&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;17&lt;/span&gt; &lt;span class="n"&gt;ambiguities&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt;
&lt;span class="n"&gt;Ambiguity&lt;/span&gt; &lt;span class="c"&gt;#1&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Integer&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SentinelArrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChainedVectorIndex&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;SentinelArrays&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;:\&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;matcox&lt;/span&gt;&lt;span class="o"&gt;\.&lt;/span&gt;&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;SentinelArrays&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;BcfVF&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="n"&gt;chainedvector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jl&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;208&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;BigInt&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Integer&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GMP&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;gmp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;jl&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;696&lt;/span&gt;

&lt;span class="n"&gt;Possible&lt;/span&gt; &lt;span class="n"&gt;fix&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;define&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;BigInt&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SentinelArrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChainedVectorIndex&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt; 

&lt;span class="n"&gt;Test&lt;/span&gt; &lt;span class="n"&gt;Summary&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Fail&lt;/span&gt;  &lt;span class="n"&gt;Total&lt;/span&gt;  &lt;span class="kt"&gt;Time&lt;/span&gt;
&lt;span class="kt"&gt;Method&lt;/span&gt; &lt;span class="n"&gt;ambiguity&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;    &lt;span class="mi"&gt;1&lt;/span&gt;      &lt;span class="mi"&gt;1&lt;/span&gt;  &lt;span class="mf"&gt;8.3&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Some&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="n"&gt;did&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;passed&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;errored&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="n"&gt;broken&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately I only find ambiguities for DataFrames, maybe I should find a package with more problems. You can also run all the underlying checks independently if you read the &lt;a href="https://juliatesting.github.io/Aqua.jl/stable/#Aqua.test_all-Tuple%7BModule%7D"&gt;Aqua documentation&lt;/a&gt;. Note that if you only want to check for ambiguities, you can also choose to call &lt;code&gt;Test.detect_ambiguities&lt;/code&gt; directly from the standard Julia Test package.&lt;/p&gt;

&lt;p&gt;A nice addition to Aqua would be a way to store the found issues in a standardized file format instead of printing them on the REPL. Similar to code coverage reporting, this can help to make overviews in automated systems. Now we would have to capture the printed output and parse that somehow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding Type Instability with JET.jl
&lt;/h2&gt;

&lt;p&gt;There is non-stop activity in the Julia community to analyze our own code for improvements. An advanced package is &lt;a href="https://github.com/aviatesk/JET.jl"&gt;JET.jl&lt;/a&gt;, which uses the Julia compiler itself to detect potential bugs and type instabilities.&lt;/p&gt;

&lt;p&gt;What is type instability? This happens when the type of a variable changes unexpectedly. Here's a simple example that outputs either an integer or a floating point variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; foo&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Type instability is bad for performance because the compiler cannot infer the types and generate optimal native code. It may also point at bugs in your code, if you did not intend to have such instability. Julia does not enforce type stability like certain languages, because it wants to remain an easy language to use. Sometimes you don't care about performance and don't want to worry about types, in which cases it's easy if you are not forced to worry.&lt;/p&gt;

&lt;p&gt;If you just want to check whether the output value can be inferred, you can use &lt;code&gt;Test.@inferred&lt;/code&gt; in your tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt;

&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nd"&gt;@inferred&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Int64&lt;/span&gt; &lt;span class="n"&gt;does&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;inferred&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Union&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Int64&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nd"&gt;@inferred&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Float64&lt;/span&gt; &lt;span class="n"&gt;does&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;inferred&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="kt"&gt;Union&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Int64&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, when you want more certainty about the internals of your code then you can turn to JET. Most of JET is doing specific method analysis with &lt;code&gt;@report_opt&lt;/code&gt; and &lt;code&gt;@report_call&lt;/code&gt; . JET can do some limited static analysis of your entire package with the &lt;code&gt;report_package&lt;/code&gt; function. Unlike &lt;code&gt;@report_call&lt;/code&gt; , this means JET doesn't know what types you want to input into your methods, so it has to make some assumptions.&lt;/p&gt;

&lt;p&gt;I do warn that the output of JET can be rather intimidating. Here's what you get when executing the example &lt;code&gt;@report_call sum("julia")&lt;/code&gt; :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/UvXUuAN7Kp0W9YDHQ5PdgYyDDTOOSayOaCShZ22G7VU/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2Zv/cDB6NWgwcGsxNjhw/a3dldzkyLlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/UvXUuAN7Kp0W9YDHQ5PdgYyDDTOOSayOaCShZ22G7VU/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2Zv/cDB6NWgwcGsxNjhw/a3dldzkyLlBORw" alt="JET REPL snip" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's just the example from the &lt;a href="https://aviatesk.github.io/JET.jl/stable/jetanalysis/#jetanalysis-quick-start"&gt;Quick Start&lt;/a&gt; page of JET.&lt;/p&gt;

&lt;p&gt;We're still investigating how to use JET, because it is pretty advanced tooling. If you just started with types and Julia, I wouldn't dive right into this. Take your time to think about what &lt;a href="https://en.wikipedia.org/wiki/Type_inference"&gt;type inference&lt;/a&gt; really means, and read the &lt;a href="https://aviatesk.github.io/JET.jl/stable/tutorial/"&gt;documentation of JET&lt;/a&gt; if you want to know more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reducing Compile Time with SnoopCompile.jl
&lt;/h2&gt;

&lt;p&gt;Optimizing your code such that the compilation times are reduced is maybe not the first thing that comes to mind when thinking about "code quality", but it can improve the user experience of your package. Nobody likes to wait long to import your package. The &lt;a href="https://github.com/timholy/SnoopCompile.jl"&gt;SnoopCompile.jl&lt;/a&gt; package helps you with analyzing your code for such improvements. It "snoops" on the compiler and reports on it's findings.&lt;/p&gt;

&lt;p&gt;There is a lengthy blog post from the SciML community on how they improved their compilation times with SnoopCompile and other tools, called &lt;a href="https://sciml.ai/news/2022/09/21/compile_time/"&gt;How Julia ODE Solve Compile Time Was Reduced From 30 Seconds to 0.1&lt;/a&gt;. Definitely read that one for more information, I will not go into details here, but I do think SnoopCompile is worth a mention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You have plenty of options to check the code quality of your Julia packages and improve the quality over time. If this feels like a daunting task as a beginning (Julia) developer, don't worry, you can slowly add these tools to your workflow over time. The most important thing is to start with a good package structure and basic testing. The fact that the Julia ecosystem is so focused on making quality easy for beginners is truly praise-worthy and will help us all in the long run.&lt;/p&gt;

&lt;p&gt;For senior developers and managers looking into these tools, one thing to remember is that lot's of code quality tooling in Julia is written with the human developer in mind. This currently limits some of the integration in automated CI tools. I believe this topic deserves some more attention in the Julia community and more support from commercial code quality tooling vendors. The good thing is that due to the standardization of the Julia package management it is very easy to get started with a uniform automation system in your organization. As the tools improve for these systems, it will be easy to incrementally add such tools to any open source or internal CI workflows.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to my colleague Matthijs den Otter for helping with the investigation. If we find better ways to monitor your Julia code quality, I intend to share that on my blog, so don't forget to &lt;a href="https://scientificcoder.com/newsletter"&gt;subscribe&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>julia</category>
      <category>codequality</category>
      <category>software</category>
      <category>tooling</category>
    </item>
    <item>
      <title>The Art of Multiple Dispatch</title>
      <dc:creator>Matthijs Cox</dc:creator>
      <pubDate>Thu, 20 Apr 2023 13:50:45 +0000</pubDate>
      <link>https://forem.julialang.org/matthijscox/the-art-of-multiple-dispatch-1hoa</link>
      <guid>https://forem.julialang.org/matthijscox/the-art-of-multiple-dispatch-1hoa</guid>
      <description>&lt;p&gt;&lt;em&gt;Read the original article and subscribe to my blog on &lt;a href="https://scientificcoder.com/the-art-of-multiple-dispatch"&gt;The Scientific Coder&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I love thinking visually by drawing doodles and schematics for my work. It's one of my favorite things to do, next to coding. When working with the Julia language, one visualization I enjoy is seeing the type space of a method that you are dispatching on. Normally I do this in my mind's eye, but let me clarify this by drawing some actual figures.&lt;/p&gt;

&lt;p&gt;To start with the basics; Julia has functions and methods. A function is simply the name, like &lt;code&gt;push!&lt;/code&gt; or &lt;code&gt;read&lt;/code&gt;. Methods are specific definitions of a function, for certain types of arguments. Take for example &lt;code&gt;push!(s::Set, x)&lt;/code&gt; or &lt;code&gt;read(io::IO)&lt;/code&gt;. From an object-oriented perspective you could say that methods are instances of functions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/sgkgDypfi2GAhAYmFNiNw8BWUK8jdIzpw29uWj9zbcY/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzLzJw/NTQwcHd3bndqaGR1/dnNpMTRiLlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/sgkgDypfi2GAhAYmFNiNw8BWUK8jdIzpw29uWj9zbcY/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzLzJw/NTQwcHd3bndqaGR1/dnNpMTRiLlBORw" alt="Dimensions" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For any given method you can consider the dispatching as slicing a part of the entire possible type space of that given function. For a given set of arguments of course. If you increase the number of arguments in the function definition, then more dimensions get added to the type space. I don't even know how to find the best written words for this, the visualization above just feels intuitive to me.&lt;/p&gt;

&lt;p&gt;Let's take the function &lt;code&gt;f&lt;/code&gt; and imagine for a moment that there are only 3 types in the whole Julia type universe: the &lt;code&gt;Float64&lt;/code&gt;, &lt;code&gt;Int64&lt;/code&gt;and the &lt;code&gt;String&lt;/code&gt;. The &lt;code&gt;Float64&lt;/code&gt;and the &lt;code&gt;Int64&lt;/code&gt;are a subtype of &lt;code&gt;Number&lt;/code&gt;, which is obvious I hope. By default in Julia if you specify no type in your function argument, then it will be assumed you mean the &lt;code&gt;Any&lt;/code&gt;type, of which every other type is a subtype.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/G8J4ZzNhTDGPE3c6kztyO_f4sNdNoqZ2_7m3qTusJPg/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2Vm/YWJybms0NmxlcGNh/bXZiY25jLlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/G8J4ZzNhTDGPE3c6kztyO_f4sNdNoqZ2_7m3qTusJPg/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2Vm/YWJybms0NmxlcGNh/bXZiY25jLlBORw" alt="Dispatching Options" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A method &lt;code&gt;f(::Any, ::Any)&lt;/code&gt; thus describes the entire space of all possible types for the function named &lt;code&gt;f&lt;/code&gt;. On the other hand, a method like &lt;code&gt;f(::Int64, ::String)&lt;/code&gt; is super concrete, it's a singular point in the type space.&lt;/p&gt;

&lt;p&gt;You can use abstract types like Number or unions like &lt;code&gt;Union{Float64, Int64}&lt;/code&gt; to capture a subset of the discrete type space. This way you can choose which part you want to define for your function, with the chosen set of types you will be dispatching on at runtime. Abstract types in Julia exist only for this dispatching purpose, to dispatch on a set of subtypes, they have no other influence on their subtypes what so ever. They are not dictators like classes in other languages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/NltuENNwIwfNzsx6rjtvUqhZLWzxrScRSe8Q3W2FFEQ/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL3Bx/aTJ3cTg0MTU2OGNs/MWc1ZWowLlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/NltuENNwIwfNzsx6rjtvUqhZLWzxrScRSe8Q3W2FFEQ/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL3Bx/aTJ3cTg0MTU2OGNs/MWc1ZWowLlBORw" alt="Diagonal dispatch" width="776" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I like these visuals. Some junior engineers wonder what "diagonal dispatch" is. I don't have any other way of explaining the concept then by just drawing it. The figure is immediately obvious. Diagonal dispatch happens when the type of all arguments is forced to be equal with &lt;code&gt;f(::T, ::T) where T&lt;/code&gt;. This truly represent a diagonal through the type space. You can see it in the example above. You can also limit the diagonal dispatch to a subset with &lt;code&gt;f(::T, ::T) where T&amp;lt;:Number&lt;/code&gt; and in higher dimensions you can be fancy like &lt;code&gt;f(::T, ::T, ::S) where {T&amp;lt;:Number, S&amp;lt;:AbstractString}&lt;/code&gt; by adding multiple of these parametric types.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/dL6gI0QPSSNl5P3POElbHz1yj0Cp39Ncp_c1oA2BArY/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2Vl/eGY1aW8zaXQ4aHQ3/MXlsY2lxLlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/dL6gI0QPSSNl5P3POElbHz1yj0Cp39Ncp_c1oA2BArY/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2Vl/eGY1aW8zaXQ4aHQ3/MXlsY2lxLlBORw" alt="Dispatch specifics" width="800" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that when you define a method twice, you have to take care that it is clear which method gets dispatched on. The compiler will prioritize the one that is most concrete, so the one that is most specific about the types. In the figure above, I ordered them from most specific to least specific. You can try for yourself to see if I ordered them correctly.&lt;/p&gt;

&lt;p&gt;For example if you define the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"any &amp;amp; any"&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Int64&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Int64&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"int &amp;amp; int"&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then most function calls will run the broadest method because that one is defined for the whole type space, but when you input two integers you will call the very specific method &lt;code&gt;f(::Int64, ::Int64)&lt;/code&gt;. Let's give it a go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"string"&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;any&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;

&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;int&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;int&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From a visual perspective, we have created an overlapping dispatch, where one method is specifically defined for the integer case &lt;code&gt;f(::Int64, ::Int64)&lt;/code&gt; and will be called when only integers are used as arguments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/eedqgwoxr2wrzEXq_gS7_6LwDSnmMmDvtlQVS1xoRwA/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2M3/cmZ5c3FzaDQzYzY0/dWgwdWcxLlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/eedqgwoxr2wrzEXq_gS7_6LwDSnmMmDvtlQVS1xoRwA/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL2M3/cmZ5c3FzaDQzYzY0/dWgwdWcxLlBORw" alt="Overlapping dispatch" width="665" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are some caveats here. If you are not careful the methods can become ambiguous and Julia won't like that. For example if you define the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"any &amp;amp; string"&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"string &amp;amp; any"&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which one of these methods should be called with &lt;code&gt;f("string", "string")&lt;/code&gt;?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"string"&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;

&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"string"&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;any&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;

&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"string"&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"string"&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ERROR&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MethodError&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;ambiguous&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;  &lt;span class="n"&gt;Candidates&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;Main&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;REPL&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="x"&gt;]&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;Main&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="n"&gt;REPL&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="x"&gt;]&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;Possible&lt;/span&gt; &lt;span class="n"&gt;fix&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;define&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yikes, that's impossible! Fortunately there is a fix proposed, by explicitly defining the ambiguous case. Though perhaps you should reconsider what your actual intentions are in this design. The visual representation below hopefully makes the mistake more clear. At first there is confusion because the two dispatches overlap and neither is more specific than the other, but we can fix it by defining a more concrete method in the conflicting area.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/R9t9N5cH8UV1zS4bAGfke16u9ryERhfftFN25FQ8Rro/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL3ps/Y29lYmVhb20ydWQ2/Y3RiODAxLlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/R9t9N5cH8UV1zS4bAGfke16u9ryERhfftFN25FQ8Rro/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL3ps/Y29lYmVhb20ydWQ2/Y3RiODAxLlBORw" alt="Method Ambiguity" width="800" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you define a lot of methods, you are creating a colorful patchwork in the type space of your function. You can come up with the craziest designs in your methods, but be careful. Finding the right balance of a few big broad abstract methods versus multiple tiny concrete methods is a true art in Julia.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://forem.julialang.org/images/yOmiRNHy3wt4VAb8osfNzkG6e0DzUqoqnJUom3kXYUY/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL3N3/dGkxeHpwMm93bDFl/MmR5cHNxLlBORw" class="article-body-image-wrapper"&gt;&lt;img src="https://forem.julialang.org/images/yOmiRNHy3wt4VAb8osfNzkG6e0DzUqoqnJUom3kXYUY/w:800/mb:500000/ar:1/aHR0cHM6Ly9mb3Jl/bS5qdWxpYWxhbmcu/b3JnL3JlbW90ZWlt/YWdlcy91cGxvYWRz/L2FydGljbGVzL3N3/dGkxeHpwMm93bDFl/MmR5cHNxLlBORw" alt="Patchwork" width="800" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;People do not often share how they visualize the code design in their mind, while I believe this really shapes the creative process. The closest visual representation in Julia I have seen is the article about &lt;a href="https://www.moll.dev/projects/effective-multi-dispatch/"&gt;Julia's dispatch with Pokemon types&lt;/a&gt;. You can read that for more detailed examples with Julia's multiple dispatch.&lt;/p&gt;

&lt;p&gt;That concludes this short artsy post, but I hope it helps the visual thinkers in the programming community! Let me know if you use different kinds of visualizations in your coding work. And don't forget to &lt;a href="https://scientificcoder.com/newsletter"&gt;subscribe to my newsletter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>julia</category>
      <category>art</category>
      <category>coding</category>
    </item>
    <item>
      <title>Embedding Julia libraries in C++</title>
      <dc:creator>Matthijs Cox</dc:creator>
      <pubDate>Thu, 21 Jul 2022 09:57:03 +0000</pubDate>
      <link>https://forem.julialang.org/matthijscox/embedding-julia-libraries-in-c-1n12</link>
      <guid>https://forem.julialang.org/matthijscox/embedding-julia-libraries-in-c-1n12</guid>
      <description>&lt;p&gt;Embedding compiled Julia libraries inside a foreign environment with a C-callable interface is an advanced topic on the border of my expertise. It's somewhat underdocumented and non-trivial, so I've made this tutorial by writing down the steps I followed myself.&lt;/p&gt;

&lt;p&gt;The fundamentals are explained in the &lt;a href="https://docs.julialang.org/en/v1/manual/embedding/"&gt;Embedding section&lt;/a&gt; in the Julia manual. For the datatypes that can be passed between C and Julia, see &lt;a href="https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/"&gt;calling-c-and-fortran-code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I will make things hard for myself and compile on Windows. Also note that I am using c++ instead of c, but most steps will be similar for c.&lt;/p&gt;

&lt;p&gt;High level the steps involved are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup a c/c++ compiler&lt;/li&gt;
&lt;li&gt;Make a Julia package&lt;/li&gt;
&lt;li&gt;Write the Julia c-interface functions&lt;/li&gt;
&lt;li&gt;Write the c++ code calling those functions&lt;/li&gt;
&lt;li&gt;Compile Julia code to a library with PackageCompiler.jl&lt;/li&gt;
&lt;li&gt;Compile c++ and link it to the Julia library&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll explain how I did these steps and especially touch upon the Julia-C interface functions and types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compiling C++
&lt;/h2&gt;

&lt;p&gt;I will compile C++ on Windows. It's notoriously difficult on Windows to find the right compiler. I got burned once on some generic MinGW compiler, creating all kinds of wrong string conversions, took us days to find out. So far the MinGW &lt;code&gt;x86_64-8.1.0-posix-seh-rt_v6-rev0&lt;/code&gt; version is working fine on my personal system. You can also use the &lt;a href="https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-170"&gt;Microsoft Visual C++ compiler tools&lt;/a&gt;, you can download the command line tools separate from the Visual Studio IDE. Make sure the right tool is added to your windows path. Use &lt;code&gt;where g++&lt;/code&gt; or &lt;code&gt;where gcc&lt;/code&gt; to find out which one you are using.&lt;/p&gt;

&lt;p&gt;Let's start at the real basics. So make a file called example.cpp.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"hello world"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now on your command line run: &lt;code&gt;g++ example.cpp -o example&lt;/code&gt;. This will compile an example.exe, which you can then run on your command line with &lt;code&gt;example.exe&lt;/code&gt; and see the output string "hello world".&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;gcc&lt;/code&gt; for c and &lt;code&gt;g++&lt;/code&gt; for c++. These functions come with a bunch of compile and link options. There are so many options... The most common ones are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-c&lt;/code&gt; (Compilation option).
Compile only. Produces .o files from source files without doing any linking.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-I[/path/to/headers]&lt;/code&gt; (Compilation option).
Include a folder with header files, like julia.h.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-o file-name&lt;/code&gt; (Link option, usually).
Use file-name as the name of the file produced by g++ (usually, this is an executable file).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-l[library-name]&lt;/code&gt; (Link option).
Link in the specified library, for example &lt;code&gt;-ljulia&lt;/code&gt; for libjulia.dll.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-L[/path/to/shared-libraries] -l[library-name]&lt;/code&gt; (Link option).
Link in the specified library from a given folder.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create a Julia package
&lt;/h2&gt;

&lt;p&gt;I assume you have basic Julia knowledge, including package development. Julia libraries are created from a package, so go ahead and make one in a folder. Simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"my/desired/package/path"&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Pkg&lt;/span&gt;&lt;span class="x"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Pkg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;generate&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyLibPackage"&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Compiling Julia
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/JuliaLang/PackageCompiler.jl"&gt;PackageCompiler.jl&lt;/a&gt; is your primary friend and documentation is improving rapidly. Perhaps in the future we will have an incredible &lt;a href="https://github.com/tshort/StaticCompiler.jl"&gt;StaticCompiler.jl&lt;/a&gt;, but that's for another time.&lt;/p&gt;

&lt;p&gt;PackageCompiler does take a few minutes to compile any Julia code, even a simple hello world. That's because all of Julia base is included, regardless of whether actually need all base functionality or not.&lt;/p&gt;

&lt;p&gt;We will be using the &lt;a href="https://julialang.github.io/PackageCompiler.jl/stable/libs.html"&gt;create_library&lt;/a&gt; functionality of PackageCompiler. The easiest way is to find some example build scripts from others and add those to your package, so let's go find one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Existing examples?
&lt;/h2&gt;

&lt;p&gt;A skeleton Julia compilation example is already available &lt;a href="https://github.com/JuliaLang/PackageCompiler.jl/tree/master/examples/MyLib"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For a pure C example implementation see Simon Byrne's &lt;a href="https://github.com/simonbyrne/libcg"&gt;libcg&lt;/a&gt;. See if you can already run that example.&lt;/p&gt;

&lt;p&gt;Steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clone the repository in a folder. You know: &lt;code&gt;git clone https://github.com/simonbyrne/libcg.git&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run the Makefile. Uh oh...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OK, running the Makefile on Windows isn't trivial either. &lt;a href="https://stackoverflow.com/questions/2532234/how-to-run-a-makefile-in-windows"&gt;StackOverflow provides some answers&lt;/a&gt;. My c/c++ mingw installation comes with &lt;code&gt;mingw32-make&lt;/code&gt;, but that doesn't work with this specific Makefile, see this &lt;a href="https://github.com/simonbyrne/libcg/issues/21"&gt;issue&lt;/a&gt;. Advise is to install Cygwin together with &lt;code&gt;make&lt;/code&gt;, because the examples repositories use a lot of shell scripting which doesn't work on Windows.&lt;/p&gt;

&lt;p&gt;OK, so this example is not so simple on Windows. In the end I decided to write my own Windows Makefile for my own c++ code and run it with &lt;code&gt;mingw32-make&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can find my personal examples in this &lt;a href="https://github.com/matthijscox/embedjuliainc/"&gt;repository called embedjuliainc&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interlude: Makefiles?
&lt;/h3&gt;

&lt;p&gt;Compiling c/c++ projects generally involves a lot of steps to compile multiple files and link libraries together. This can become a complex build process and you don't want to type all commands manually all the time. So people made build tools! Yay! Typically these come with their own kind of scripting language that you need to learn. Hmm, OK, just do it. It's also generally Unix oriented, not Windows. Make is a one common build tool, here's a &lt;a href="https://makefiletutorial.com/"&gt;Makefile tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As an example, I enjoyed this &lt;a href="https://earthly.dev/blog/g++-makefile/"&gt;g++ makefile example&lt;/a&gt;. It explains all compilation steps and how to make a Makefile for our simple example c++ program above. Very informative, please read and try it out!&lt;/p&gt;

&lt;h3&gt;
  
  
  Interlude: Name Mangling
&lt;/h3&gt;

&lt;p&gt;Another thing that is different in all my examples below, is that c++ mangles the names of functions. That means that a function &lt;code&gt;f(int)&lt;/code&gt; get's turning into something like &lt;code&gt;__f_i(int)&lt;/code&gt;. To avoid this we need to use &lt;a href="https://www.geeksforgeeks.org/extern-c-in-c/"&gt;extern C&lt;/a&gt; whenever we define function interfaces. This took me a while to figure out, so a lesson learned the hard way!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"julia_init.h"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Basic Types
&lt;/h2&gt;

&lt;p&gt;I created an example of basic type data transfer between Julia and c++ in this &lt;a href="https://github.com/matthijscox/embedjuliainc/tree/main/basic"&gt;repository&lt;/a&gt;. It contains implementations of the following data types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Booleans&lt;/li&gt;
&lt;li&gt;Integers&lt;/li&gt;
&lt;li&gt;Doubles&lt;/li&gt;
&lt;li&gt;Strings&lt;/li&gt;
&lt;li&gt;Structs&lt;/li&gt;
&lt;li&gt;Arrays&lt;/li&gt;
&lt;li&gt;Enumerations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a full comparison look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Julia source code file &lt;a href="https://github.com/matthijscox/embedjuliainc/blob/main/basic/BasicTypes/src/BasicTypes.jl"&gt;BasicTypes.jl&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The C++ file calling into the Julia library in &lt;a href="https://github.com/matthijscox/embedjuliainc/blob/main/basic/main-cpp/basic.cpp"&gt;basic.cpp&lt;/a&gt; which uses &lt;a href="https://github.com/matthijscox/embedjuliainc/blob/main/basic/BasicTypes/build/basic.h"&gt;basic.h&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In general Julia's &lt;a href="https://docs.julialang.org/en/v1/base/c/#C-Interface"&gt;C interface documentation&lt;/a&gt; is your friend.&lt;/p&gt;

&lt;p&gt;The typical pattern is straightforward, this Julia code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nd"&gt;@ccallable&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; test_int64&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myInt64&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Int64&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Int64&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;myInt64&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can call with such c++ code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int64_t&lt;/span&gt; &lt;span class="nf"&gt;test_int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int64_t&lt;/span&gt; &lt;span class="n"&gt;myInt64&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;int64_t&lt;/span&gt; &lt;span class="n"&gt;myInt64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;9006271&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;test_int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myInt64&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Header file
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;PackageCompiler.create_library&lt;/code&gt; function also likes to receive a header file. So please write all your c/c++ interface types and functions inside this header file. I wonder if this header file could be created automatically from all the &lt;code&gt;Base.@ccallable&lt;/code&gt; function signatures? Now you have to manually keep the Julia source code and the header file in sync.&lt;/p&gt;

&lt;h3&gt;
  
  
  Struct types
&lt;/h3&gt;

&lt;p&gt;As the manual says in the section &lt;a href="https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/#Struct-Type-Correspondences"&gt;"Struct Type Correspondences"&lt;/a&gt; you can pass structs. Fixed size arrays in c/c++ map onto the &lt;code&gt;NTuple&lt;/code&gt; in Julia.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Warning! Be absolutely certain that the Julia struct definition matches the c struct definition!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nested structs work just fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; ChildStruct&lt;/span&gt;
    &lt;span class="n"&gt;ChildStructId&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; ParentStruct&lt;/span&gt;
    &lt;span class="n"&gt;ParentStructId&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt;
    &lt;span class="n"&gt;myChildStruct&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ChildStruct&lt;/span&gt;
    &lt;span class="n"&gt;staticArray&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;NTuple&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Cint&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nd"&gt;@ccallable&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; test_nested_structs&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myParentStruct&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ParentStruct&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ParentStruct&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;myParentStruct&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The corresponding C/C++ interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;ChildStruct&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ChildStructId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;ParentStruct&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ParentStructId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ChildStruct&lt;/span&gt; &lt;span class="n"&gt;myChildStruct&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;staticArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;ParentStruct&lt;/span&gt; &lt;span class="nf"&gt;test_nested_structs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ParentStruct&lt;/span&gt; &lt;span class="n"&gt;myParentStruct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Passing by reference
&lt;/h3&gt;

&lt;p&gt;If you want to avoid any copying and additional memory allocation, you will have to pass the data by reference as a pointer. A typical example is to pass an array by reference. In the example code I pass an &lt;code&gt;Array{Cint}&lt;/code&gt;. Note that you also need to pass the dimensions of the array, in this case only the length, since we assume it's a vector.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nd"&gt;@ccallable&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; test_array&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myArrayPtr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Ptr&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="n"&gt;myArraySize&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cvoid&lt;/span&gt;
    &lt;span class="n"&gt;myArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unsafe_wrap&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Array&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="n"&gt;myArrayPtr&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;myArraySize&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;own&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;# do stuff, mutating an element will mutate the original C memory, be careful&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mutating
&lt;/h3&gt;

&lt;p&gt;Let's pass a struct by reference and mutate it. You can first load the entire struct with &lt;code&gt;unsafe_load&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nd"&gt;@ccallable&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; test_nested_structs_ptr&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myParentStructPtr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Ptr&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ParentStruct&lt;/span&gt;&lt;span class="x"&gt;})&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cvoid&lt;/span&gt;
    &lt;span class="n"&gt;myParentStruct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unsafe_load&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;myParentStructPtr&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;myParentStruct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;myChildStruct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChildStruct&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Cvoid&lt;/span&gt;&lt;span class="x"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For arrays you can first &lt;code&gt;unsafe_wrap&lt;/code&gt; like in the section above. Or you can immediately &lt;code&gt;unsafe_store!&lt;/code&gt; on an individual element. As always be very careful with these operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nested variable sized structs
&lt;/h3&gt;

&lt;p&gt;Be careful with placing variable-sized arrays inside structs (this includes strings). You will have to somehow pass along the array size and manually unwrap such complexity. I still have to write a complex example for this. The Julia manual has a very minimal example in the &lt;a href="https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/#Struct-Type-Correspondences"&gt;"Calling C and Fortran"&lt;/a&gt; section.&lt;/p&gt;

&lt;p&gt;For example, I would like to pass such a structure by reference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; VarSizedStruct&lt;/span&gt;
    &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt;
    &lt;span class="n"&gt;varArray&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Array&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Cdouble&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cstring&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; NestedVarStruct&lt;/span&gt;
    &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt;
    &lt;span class="n"&gt;varArray&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Array&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;VarSizedStruct&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I don't know if it is a smart thing to do. You'll have to manually interpret the bytes...&lt;/p&gt;

&lt;p&gt;I think the best way to go, is to place pointers inside the structs and to manually &lt;code&gt;unsafe_wrap&lt;/code&gt; every array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; VarSizedStruct&lt;/span&gt;
    &lt;span class="n"&gt;lenArray&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt;
    &lt;span class="n"&gt;varArrayPtr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Ptr&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Cdouble&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;lenString&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt; &lt;span class="c"&gt;# in case the string is not NUL-terminated&lt;/span&gt;
    &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Ptr&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Uint8&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; NestedVarStruct&lt;/span&gt;
    &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt;
    &lt;span class="n"&gt;varArrayPtr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Ptr&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;VarSizedStruct&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; Base.@ccallable&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nestedPtr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Ptr&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;NestedVarStruct&lt;/span&gt;&lt;span class="x"&gt;})&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cvoid&lt;/span&gt;
    &lt;span class="n"&gt;nested&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unsafe_load&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nestedPtr&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nested&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;
    &lt;span class="n"&gt;struct_array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unsafe_wrap&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Array&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;VarSizedStruct&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="n"&gt;nested&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;varArrayPtr&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;own&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;last_struct&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;struct_array&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="x"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;last_double_array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unsafe_wrap&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Array&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Cdouble&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="n"&gt;last_struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;varArrayPtr&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lenArray&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;own&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;last_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;unsafe_string&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_struct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lenString&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Cvoid&lt;/span&gt;&lt;span class="x"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Basically you are not passing along the struct with data, but a collection of pointers and lengths. You'll have to then manually convert the data to an internal Julia representation of your choosing. It seems error prone and feels like it could be automated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Garbage Collector
&lt;/h2&gt;

&lt;p&gt;The manual is clear on &lt;a href="https://docs.julialang.org/en/v1/manual/embedding/#Memory-Management"&gt;memory management&lt;/a&gt; from within c/c++. You can even disable the garbage collector if you want.&lt;/p&gt;

&lt;p&gt;One thing we ran into while testing the c-callable Julia functions from within a Julia script, is that the garbage collector may remove your object even while the function is executing. This can happen when passing pointers instead of objects and leads to horribly unexpected segmentation faults. Please use the &lt;code&gt;GC.@preserve&lt;/code&gt; for those cases.&lt;/p&gt;

&lt;p&gt;I placed an example in the precompile statements file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Cint&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="x"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;arr_pointer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Ptr&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt;&lt;span class="x"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;pointer_from_objref&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="x"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;len_arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cconvert&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="x"&gt;))&lt;/span&gt;
&lt;span class="c"&gt;# please garbage collector, preserve my array during execution&lt;/span&gt;
&lt;span class="n"&gt;GC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nd"&gt;@preserve&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt; &lt;span class="n"&gt;test_array&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr_pointer&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len_arr&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Error handling
&lt;/h2&gt;

&lt;p&gt;A typical old C way of error handling is to always return an integer on the C interface. The Julia code is then responsible for catching errors and returning the corresponding error integer. Any other desired output arguments are passed as mutable input parameters on the C interface. If you want the error messages as well, you could also pass along a struct with the error code/type and a Cstring with the error message. I've added an example with an &lt;a href="https://github.com/matthijscox/embedjuliainc/tree/main/exceptions"&gt;ExceptionHandler.jl&lt;/a&gt; package for this case to my repository.&lt;/p&gt;

&lt;p&gt;Here's a simple example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;error_code&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Exception&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nd"&gt;@ccallable&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; something&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputPtr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Ptr&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="n"&gt;outputPtr&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Ptr&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt;&lt;span class="x"&gt;})&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;
    &lt;span class="n"&gt;resultCode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;
        &lt;span class="c"&gt;# do stuff&lt;/span&gt;
    &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;
        &lt;span class="n"&gt;resultCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;error_code&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resultCode&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But that is not what I am looking for. I want a way to catch Julia exceptions inside c++. The Julia manual &lt;a href="https://docs.julialang.org/en/v1/manual/embedding/#Exceptions"&gt;embedding section on exceptions&lt;/a&gt; is not clear on how to do this for native &lt;code&gt;Base.@ccallable&lt;/code&gt; functions. Through experimentation I found out that exceptions cannot be caught by a regular try/catch block inside the c++ code wrapping around the julia library call.&lt;/p&gt;

&lt;p&gt;Let's say we have a function that throws errors on the c-interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nd"&gt;@ccallable&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; throw_basic_error&lt;/span&gt;&lt;span class="x"&gt;()&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Cint&lt;/span&gt;
    &lt;span class="n"&gt;throw&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ErrorException&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"this is an error"&lt;/span&gt;&lt;span class="x"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Missed exceptions
&lt;/h3&gt;

&lt;p&gt;This would be an expected way to catch errors, but it doesn't work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;throw_basic_error&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt; a standard exception was caught, with message '"&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;what&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt; unknown exception caught"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When running this code, you will see an error like &lt;code&gt;fatal: error thrown and no exception handler available.&lt;/code&gt;. Our current assumption is that this is due to Julia initializing in another thread or process than the c++ code itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Catch those exceptions
&lt;/h3&gt;

&lt;p&gt;After some digging we found the &lt;code&gt;JL_TRY&lt;/code&gt; and &lt;code&gt;JL_CATCH&lt;/code&gt; macros in the Julia header file. These can be used to catch Julia exceptions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;JL_TRY&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;throw_basic_error&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;JL_CATCH&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;jl_value_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;errs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jl_stderr_obj&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"A Julia exception was caught"&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;jl_value_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;showf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jl_get_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jl_base_module&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"showerror"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showf&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;jl_call2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jl_current_exception&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;jl_printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jl_stderr_stream&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To print the error type and message, you will have to use functions directly from the Julia runtime. We did not yet find a nice and easy way to convert the Julia exception into a c++ exception.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outlook
&lt;/h2&gt;

&lt;p&gt;The package &lt;a href="https://github.com/analytech-solutions/CBinding.jl"&gt;CBinding.jl&lt;/a&gt; can automatically generate the Julia types from a c header file. There is a lot of knowledge in that package, so I should investigate it better. I also wonder if it's possible to do the opposite: to generate a c header from Julia types and functions.&lt;/p&gt;

&lt;p&gt;Other interesting packages are &lt;a href="https://github.com/JuliaInterop/Cxx.jl"&gt;Cxx.jl&lt;/a&gt; and &lt;a href="https://github.com/JuliaInterop/CxxWrap.jl"&gt;CxxWrap.jl&lt;/a&gt;. These packages focus on embedding c++ (libraries) inside Julia, but again contain a lot of knowledge and some examples on embedding Julia inside c/c++.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Embedding in c/c++ is non-trivial. I advise to avoid embedding if you can ;) If you cannot avoid embedding, then use the examples from this post, but I do not guarantee that all my examples are safe and robust. I did not yet create examples with complicated nested variable sized structures and arrays, that's for another time. For now I'd advise to keep the c-interface as simple as possible. Good luck!&lt;/p&gt;

&lt;h3&gt;
  
  
  Acknowledgements
&lt;/h3&gt;

&lt;p&gt;Special acknowledgements to Daan Sperber, Biao Xu and Evangelos Paradas for helping me figure out a lot of the steps involved.&lt;/p&gt;

</description>
      <category>embedding</category>
    </item>
    <item>
      <title>Julia Data Modeling: A Pointy Example</title>
      <dc:creator>Matthijs Cox</dc:creator>
      <pubDate>Wed, 20 Jul 2022 12:45:42 +0000</pubDate>
      <link>https://forem.julialang.org/matthijscox/julia-data-modeling-a-pointy-example-2omd</link>
      <guid>https://forem.julialang.org/matthijscox/julia-data-modeling-a-pointy-example-2omd</guid>
      <description>&lt;p&gt;Julia's high performance gives the developer a lot of freedom in their choice of data structures. The downside of this freedom is that you need to spend more time thinking about the optimal data model for your code.&lt;/p&gt;

&lt;p&gt;In a low performance language you are often restrained by the interface of the underlying high performance library. For example, in the MATLAB language or the Python Numpy package you are encouraged to make vectors of only numbers.&lt;/p&gt;

&lt;p&gt;In Julia you can define your own custom types, which can be just as performant, or even more performant depending on your use case, than the already available types.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lot's of Points
&lt;/h2&gt;

&lt;p&gt;To illustrate the possibilities, I'll take a simple example that I personally encountered a lot. You've got some data points on an XY plane and the data is labeled as valid or not.&lt;/p&gt;

&lt;p&gt;The straightforward way to model this data (coming from a vectorized framework) is to define these as vectors.&lt;/p&gt;

&lt;p&gt;To keep them easily together in Julia, you'll then want to put them in a custom type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; VectorData&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;validx&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;validy&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason that vectors (of primitive types) are often performant is due to how your computer stores memory in data. When you apply operations that need to iterate over &lt;code&gt;x&lt;/code&gt; for example, the compact memory layout is quite ideal. You can read this excellent article about &lt;a href="https://viralinstruction.com/posts/hardware/"&gt;What scientists must know about hardware to write fast code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So this can be a very good data structure. For example for multiplying your &lt;code&gt;x&lt;/code&gt; values with a matrix.&lt;/p&gt;

&lt;p&gt;If you spend a lot of time iterating over the data points however, like filtering the valid data based on some function, things become a bit more messy.&lt;/p&gt;

&lt;p&gt;Also some developer might suddenly decide not all vectors in &lt;code&gt;VectorData&lt;/code&gt; need to be equally long. Or the user of your data structure accidentally only changes one vector. If you want the vectors to be mutable, yet always of equal length, then you should check the vector lengths in all your functions to be safe :(&lt;/p&gt;

&lt;p&gt;Let's try an alternative.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; PointData&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;
    &lt;span class="n"&gt;validx&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;
    &lt;span class="n"&gt;validy&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; PointVector&lt;/span&gt;
   &lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PointData&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that I put the vector of &lt;code&gt;PointData&lt;/code&gt; into a struct, which just makes function dispatching more pleasant.&lt;/p&gt;

&lt;p&gt;Let's write our desired filter function and try them both. Decide for yourself which solution you find most readable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; within_threshold&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;:&lt;/span&gt;&lt;span class="kt"&gt;Real&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;VectorData&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;keep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validx&lt;/span&gt; &lt;span class="o"&gt;.&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validy&lt;/span&gt; &lt;span class="o"&gt;.&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;within_threshold&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Ref&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="x"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;VectorData&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;keep&lt;/span&gt;&lt;span class="x"&gt;],&lt;/span&gt; &lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;keep&lt;/span&gt;&lt;span class="x"&gt;],&lt;/span&gt; &lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validx&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;keep&lt;/span&gt;&lt;span class="x"&gt;],&lt;/span&gt; &lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validy&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;keep&lt;/span&gt;&lt;span class="x"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; keep_point&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PointData&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validx&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validy&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;within_threshold&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;AbstractArray&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PointData&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;keep_point&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="x"&gt;),&lt;/span&gt; &lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PointVector&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PointVector&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="x"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can quickly try both functions out by constructing some example data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; Base.convert&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Type&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PointVector&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;VectorData&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;points&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PointData&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validx&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validy&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PointVector&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="n"&gt;BenchmarkTools&lt;/span&gt;
&lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10_000_000&lt;/span&gt; &lt;span class="c"&gt;# making the vectors do not fit in my computer's cache ;)&lt;/span&gt;
&lt;span class="n"&gt;vd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VectorData&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="x"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="x"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="x"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="x"&gt;))&lt;/span&gt;

&lt;span class="nd"&gt;@benchmark&lt;/span&gt; &lt;span class="n"&gt;filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vd&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;BenchmarkTools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Trial&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;175&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;evaluation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
 &lt;span class="n"&gt;Range&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;25.246&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="mf"&gt;62.595&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;  &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="mf"&gt;27.22&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
 &lt;span class="kt"&gt;Time&lt;/span&gt;  &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="mf"&gt;26.840&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;              &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
 &lt;span class="kt"&gt;Time&lt;/span&gt;  &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="n"&gt;σ&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="mf"&gt;28.581&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt;  &lt;span class="mf"&gt;4.728&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;  &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="n"&gt;σ&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;1.55&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt;  &lt;span class="mf"&gt;5.52&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;

 &lt;span class="n"&gt;Memory&lt;/span&gt; &lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;6.60&lt;/span&gt; &lt;span class="n"&gt;MiB&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allocs&lt;/span&gt; &lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;14.&lt;/span&gt;

&lt;span class="n"&gt;pv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;convert&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PointVector&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vd&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@benchmark&lt;/span&gt; &lt;span class="n"&gt;filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pv&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;BenchmarkTools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Trial&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;170&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;evaluation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
 &lt;span class="n"&gt;Range&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;21.897&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="mf"&gt;85.568&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;  &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="mf"&gt;8.27&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
 &lt;span class="kt"&gt;Time&lt;/span&gt;  &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="mf"&gt;28.346&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;              &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="mf"&gt;0.72&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
 &lt;span class="kt"&gt;Time&lt;/span&gt;  &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="n"&gt;σ&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="mf"&gt;29.538&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt;  &lt;span class="mf"&gt;7.879&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;  &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="n"&gt;σ&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;10.11&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="mf"&gt;9.53&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;

 &lt;span class="n"&gt;Memory&lt;/span&gt; &lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;228.88&lt;/span&gt; &lt;span class="n"&gt;MiB&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allocs&lt;/span&gt; &lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;4.&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case it turns the times are roughly equal. My PointVector solution is slightly faster, but does use way more memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interlude: Filtering better
&lt;/h2&gt;

&lt;p&gt;I am a little annoyed at the memory usage of the filter function. So I am exploring how to improve that here.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Base.filter()&lt;/code&gt; function might be the memory consumer. If you write a list comprehension it actually use &lt;code&gt;Iterators.filter&lt;/code&gt;, so these two solutions behave equally. Less memory usage, but slightly slower:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;AbstractArray&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PointData&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;points&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;keep_point&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="x"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;AbstractArray&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PointData&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;collect&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Iterators&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;keep_point&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="x"&gt;),&lt;/span&gt; &lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="x"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nd"&gt;@benchmark&lt;/span&gt; &lt;span class="n"&gt;filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pv&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;BenchmarkTools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Trial&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;117&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;evaluation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
 &lt;span class="n"&gt;Range&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;36.909&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="mf"&gt;101.812&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;  &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
 &lt;span class="kt"&gt;Time&lt;/span&gt;  &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="mf"&gt;39.738&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;               &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
 &lt;span class="kt"&gt;Time&lt;/span&gt;  &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="n"&gt;σ&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="mf"&gt;42.855&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt;   &lt;span class="mf"&gt;7.999&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;  &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="n"&gt;σ&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;1.13&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="mf"&gt;3.73&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;

 &lt;span class="n"&gt;Memory&lt;/span&gt; &lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;14.26&lt;/span&gt; &lt;span class="n"&gt;MiB&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allocs&lt;/span&gt; &lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;14.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I can also define the functionality myself. You can see it's pretty much equal to the list comprehension.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;:&lt;/span&gt;&lt;span class="kt"&gt;AbstractArray&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PointData&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;new_points&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="x"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;points&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;keep_point&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;push!&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_points&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;new_points&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nd"&gt;@benchmark&lt;/span&gt; &lt;span class="n"&gt;filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pv&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;BenchmarkTools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Trial&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;116&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;evaluation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
 &lt;span class="n"&gt;Range&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;41.746&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="mf"&gt;57.218&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;  &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="mf"&gt;22.16&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
 &lt;span class="kt"&gt;Time&lt;/span&gt;  &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="mf"&gt;42.415&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;              &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
 &lt;span class="kt"&gt;Time&lt;/span&gt;  &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="n"&gt;σ&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="mf"&gt;43.246&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt;  &lt;span class="mf"&gt;2.438&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;  &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="n"&gt;σ&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;1.21&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt;  &lt;span class="mf"&gt;4.03&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;

 &lt;span class="n"&gt;Memory&lt;/span&gt; &lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;14.26&lt;/span&gt; &lt;span class="n"&gt;MiB&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allocs&lt;/span&gt; &lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;14.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It seems I can reduce memory usage at the cost of some runtime performance. In the source code of &lt;code&gt;Base.filter&lt;/code&gt; I see that it pre-allocates a new vector and shrinks it afterwards, while in this code we grow the new vector dynamically. I'm keeping this info here for future reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  More point possibilities
&lt;/h2&gt;

&lt;p&gt;Having to choose between an array of structs, or a struct of arrays, is a typical scenario while coding in Julia. The best choice really depends on what you intend to do most with your data. If performance is not the issue, then I prefer the array of structs for reasons of clarity (that means the &lt;code&gt;PointVector&lt;/code&gt; in the above example).&lt;/p&gt;

&lt;p&gt;But let's not stop there and explore some more options together.&lt;/p&gt;

&lt;p&gt;Why not accept the fact that we have two points intertwined in our data model?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; Point&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; TwoPoints&lt;/span&gt;
    &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; VectorTwoPoints&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;TwoPoints&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or pair up the value and valid field. Perhaps this is a common pattern in your codebase to flag any value as valid or not?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; ValidValue&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;
    &lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; VectorPointValues&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ValidValue&lt;/span&gt;&lt;span class="x"&gt;}}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or accept that we always have a value and a valid per direction. The interesting thing here is that we can extend the directions easily in the future if we want to go 3D for example. To label the direction, we could use an enum, but those are not popular in Julia. One reason is that you cannot easily dispatch on enums. So you might find something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;abstract type&lt;/span&gt;&lt;span class="nc"&gt; Direction&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; X&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;:&lt;/span&gt; &lt;span class="n"&gt;Direction&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; Y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;:&lt;/span&gt; &lt;span class="n"&gt;Direction&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; DirectionalValidValue&lt;/span&gt;
    &lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Direction&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;
    &lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; VectorDirectionalValues&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;DirectionalValidValue&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we could go full circle and just make a struct array again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; DirectionalVectorData&lt;/span&gt;
    &lt;span class="n"&gt;direction&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;:&lt;/span&gt;&lt;span class="n"&gt;Direction&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This last one might be best if we often find ourselves concatenating the x and y value from the initial structure. For example if we want to fit the x and y data together in a 2D model.&lt;/p&gt;

&lt;p&gt;I'm not going to test the filtering performance of all of these. I expect roughly equal performance as the &lt;code&gt;PointVector&lt;/code&gt; solution, with a little extra overhead if we use structs inside structs.&lt;/p&gt;

&lt;p&gt;The ideal structures will depend on your own use case; what you do with the data in the functions you write. I'm still learning what is best for my own use cases. A structure of arrays seems to be the first choice for performance, assuming your data fits into memory as continuous vectors. DataFrames.jl stores each column as a vector for this purpose. But the desire to want both a struct array and an array of structs is a common pattern as well. So common that it has it's own package: &lt;a href="https://github.com/JuliaArrays/StructArrays.jl"&gt;StructArrays.jl&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  StructArrays
&lt;/h2&gt;

&lt;p&gt;Let's have a brief look at StructArrays. I'm re-using the data generated in the example from the beginning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="n"&gt;StructArrays&lt;/span&gt;

&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;StructArray&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;10000000&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="n"&gt;StructArray&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="x"&gt;})&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;eltype&lt;/span&gt; &lt;span class="n"&gt;PointData&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
 &lt;span class="n"&gt;PointData&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8342412444868733&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.7156389385059589&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;⋮&lt;/span&gt;
 &lt;span class="n"&gt;PointData&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.21446860650049493&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.23189128521923086&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# you can get the properties again&lt;/span&gt;
&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sa&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
&lt;span class="mi"&gt;10000000&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
 &lt;span class="mf"&gt;0.8342412444868733&lt;/span&gt;
 &lt;span class="n"&gt;⋮&lt;/span&gt;
 &lt;span class="mf"&gt;0.21446860650049493&lt;/span&gt;

&lt;span class="c"&gt;# we can apply our filter function on it&lt;/span&gt;
&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sa&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;314598&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="n"&gt;StructArray&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="x"&gt;},&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="x"&gt;})&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;eltype&lt;/span&gt; &lt;span class="n"&gt;PointData&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
 &lt;span class="n"&gt;PointData&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.09048345510701994&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.320553989305556&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
 &lt;span class="n"&gt;⋮&lt;/span&gt;
 &lt;span class="n"&gt;PointData&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.11419461083293259&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.34645035134668634&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;julia&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;@benchmark&lt;/span&gt; &lt;span class="n"&gt;filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sa&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;BenchmarkTools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Trial&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;73&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;evaluation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
 &lt;span class="n"&gt;Range&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;63.260&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="mf"&gt;92.607&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;  &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="mf"&gt;14.19&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
 &lt;span class="kt"&gt;Time&lt;/span&gt;  &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="mf"&gt;66.733&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;              &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
 &lt;span class="kt"&gt;Time&lt;/span&gt;  &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="n"&gt;σ&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="mf"&gt;68.442&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt;  &lt;span class="mf"&gt;5.277&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;  &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="n"&gt;σ&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;0.48&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt;  &lt;span class="mf"&gt;2.31&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;

 &lt;span class="n"&gt;Memory&lt;/span&gt; &lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;14.26&lt;/span&gt; &lt;span class="n"&gt;MiB&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allocs&lt;/span&gt; &lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;14.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately it's slower than the direct implementations, StructArrays seems to add a bit of overhead. But the convenience might be worth it for you, and maybe you do not spend that much time iterating over the rows/elements of the struct array.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom struct array implementation
&lt;/h2&gt;

&lt;p&gt;If you want to build your own custom struct array, you'll have to write your own iterators and other functionality. It's more work, but is it worth it? Let's see how it goes.&lt;/p&gt;

&lt;p&gt;Basically I will just extend the &lt;code&gt;VectorData&lt;/code&gt; type and link it to the &lt;code&gt;PointData&lt;/code&gt; type via iterate and getindex and such. I will copy the structures here for clarity again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; PointData&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;
    &lt;span class="n"&gt;validx&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;
    &lt;span class="n"&gt;validy&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="nc"&gt; VectorData&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Float64&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;validx&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;validy&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Vector&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="x"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c"&gt;# remember there is some danger in this assumption&lt;/span&gt;
&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;VectorData&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eachindex&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;VectorData&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eachindex&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IteratorSize&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Type&lt;/span&gt;&lt;span class="x"&gt;{&lt;/span&gt;&lt;span class="n"&gt;VectorData&lt;/span&gt;&lt;span class="x"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HasLength&lt;/span&gt;&lt;span class="x"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;# I stole this function from AbstractArrays.jl, after reading StructArrays.jl&lt;/span&gt;
&lt;span class="c"&gt;# we could also choose to make VectorData &amp;lt;: AbstractArray&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; Base.iterate&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;VectorData&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eachindex&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="x"&gt;),))&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iterate&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nb"&gt;nothing&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;nothing&lt;/span&gt;
    &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="x"&gt;]],&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="x"&gt;],&lt;/span&gt; &lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tail&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; Base.getindex&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;VectorData&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Integer&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PointData&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="x"&gt;],&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="x"&gt;],&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validx&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="x"&gt;],&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validy&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;idx&lt;/span&gt;&lt;span class="x"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c"&gt;# defining my own filter function, not sure if there is a better way&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; Base.filter&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kt"&gt;Function&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;VectorData&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;keep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Int64&lt;/span&gt;&lt;span class="x"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;enumerate&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;push!&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keep&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;VectorData&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;keep&lt;/span&gt;&lt;span class="x"&gt;],&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;keep&lt;/span&gt;&lt;span class="x"&gt;],&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validx&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;keep&lt;/span&gt;&lt;span class="x"&gt;],&lt;/span&gt; &lt;span class="n"&gt;A&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;validy&lt;/span&gt;&lt;span class="x"&gt;[&lt;/span&gt;&lt;span class="n"&gt;keep&lt;/span&gt;&lt;span class="x"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can use iteration to filter the points:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="nf"&gt; filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;VectorData&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;keep_point&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="x"&gt;),&lt;/span&gt; &lt;span class="n"&gt;pts&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's look at the filtering performance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight julia"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="n"&gt;BenchmarkTools&lt;/span&gt;
&lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10_000_000&lt;/span&gt;
&lt;span class="n"&gt;vd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VectorData&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="x"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="x"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="x"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="x"&gt;))&lt;/span&gt;

&lt;span class="nd"&gt;@benchmark&lt;/span&gt; &lt;span class="n"&gt;filter_points&lt;/span&gt;&lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vd&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;BenchmarkTools&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Trial&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;82&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="n"&gt;evaluation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
 &lt;span class="n"&gt;Range&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;54.039&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="mf"&gt;83.368&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;  &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="n"&gt;max&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;…&lt;/span&gt; &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
 &lt;span class="kt"&gt;Time&lt;/span&gt;  &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="mf"&gt;60.138&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;              &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;median&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
 &lt;span class="kt"&gt;Time&lt;/span&gt;  &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="n"&gt;σ&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="mf"&gt;61.772&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt;  &lt;span class="mf"&gt;5.472&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;  &lt;span class="n"&gt;┊&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt; &lt;span class="x"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="n"&gt;σ&lt;/span&gt;&lt;span class="x"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="mf"&gt;1.02&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;±&lt;/span&gt; &lt;span class="mf"&gt;3.27&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;

 &lt;span class="n"&gt;Memory&lt;/span&gt; &lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;10.61&lt;/span&gt; &lt;span class="n"&gt;MiB&lt;/span&gt;&lt;span class="x"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allocs&lt;/span&gt; &lt;span class="n"&gt;estimate&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;21.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You see it's hard to do a much better job than StructArrays. And definitely hard to beat an actual struct of arrays.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
