<p>As a starting developer, I worked with Pascal and Delphi. Later on, I came in contact with C++ and Visual Basic. All those are native languages, which means that their compiled binaries were executables, dynamic libraries (<code>*.dll</code> or <code>*.so</code>), to be launched on the underlying platform (Windows, UNIX, ...) and the process of compiling was not reversible.</p>
<p>Later on, I heard about Java. A strange language, in the sense that it does not get compiled into binaries which run directly on the platform, but on some &quot;runtime engine&quot;, and those could run the same compiled Java sources (so-called bytecode) on whatever platform. Another weird thing is that the compilation process was reversible: Java compiled binaries can be decompiled!</p>
<p>Some years ago, I worked (for a very short and difficult period) for a firm, where programming was done in ABL (or Progress, as they called it). That language had similar properties as Java: working in a runtime environment and being decompilable.</p>
<p>Just out of curiosity, I wonder if both properties are linked, hence these two questions:</p>
<ol>
<li>Is it possible to have a computer language, being both decompilable <strong>and</strong> not needing a runtime engine?</li>
<li>How about a computer language, launched using a runtime engine but not being decompilable, would this make sense?</li>
</ol>
<p>P.S.1 the ideal tag for this question is &quot;language-lawyer&quot;, but this tag only exists on StackOverflow. Is this the right place for this question or do I need to migrate it to StackOverflow?<br />
P.S.2 currently I'm working with C#. This compiles to executables or DLLs, a &quot;decompiler&quot; (JetBrains) exists, but the results are very disappointing, hence my first question.</p>
<p><strong>Edit</strong><br />
This is how I understand a compilation being reversible:
Compiling source code is something which is done in several steps, some of those are reversible, some are not, and apparently the first steps are reversible. Binary code being decompilable means that only the first (reversible) steps have been executed. This means that decompilable compilers only go up to a certain depth.<br />
Managed code also means that the compilation does not go up to the final depth.<br />
Hence my (apparently wrong) idea:<br />
<em>Would there be a link between &quot;decompilable depth&quot; and &quot;managed depth&quot;?</em></p>

<compilers><language-comparison>
What's the relation between a language being managed and its compiler being reversible?
CC BY-SA 4.0
2024-02-22T16:16:07.930Z
"apparently the first steps are reversible" Could you give a reference to where you read this? Even what is typically the very first stage of compliation (tokenizing the input) is not reversible as it will often throw away things like insignificant whitespace etc.
Philip Kendall
CC BY-SA 4.0
2024-02-23T15:24:16.157Z
This question seems more appropriate for [langdev.se].
Barmar
CC BY-SA 4.0
2024-02-23T18:12:24.123Z
Not all pascals compiled to machine code. Some of the early pascals for microcomputers  (UCSD( compiled to pcode. This was then run by a pcode engine at runtime. Compiling to machine code or byte code is choice that can made by implementers. It is not fixed per language.
Walter
CC BY-SA 4.0
2024-02-28T20:25:05.377Z
Information is typically thrown away in the compilation process because it is not needed.  Variable names, comments, compiler directives.  If you want to reverse the process you need to save it _somewhere_ - frequently this is called debug information.
Thorbjørn Ravn Andersen
<p>First you need a good understanding of the difference between compiled and interpreted.  This is not a matter of language, but of distribution and process.  If what is distributed and processed (executed) is what the developer wrote, then it’s interpreted.  If what is distributed has been transformed (ignoring stripping of white space and comments and possibly obscuration), it’s compiled.</p>
<p>With interpreted distribution, there is nothing to decompile, what is available is the original.</p>
<p>With compilation, the transformation is almost certainly going to be lossy, ie you can’t go back and forth between the two without loss because that’s not a design goal and adding the ability to do so would generally be a waste — you are looking for the new format, not to allow someone else to get the source you already have.</p>
<p>That said, when the destination is an intermediate format, one which is itself expected to be compiled/interpreted , it tends to keep a similar structure and the same function names. Global optimization and inline methods are generally not done.  All of which means that the compiled code is still somewhat similar to the original code.</p>
<p>Despite this similar structure and at least some names being retained, it’s still intended to be a one way process, and is going to be lossy, just not as lossy as would be the case if it was being compiled to a machine code.</p>
<p>One other point, sometimes compilers generate debugging information that allows associating the compiled code back to the original source code.</p>
<p>Anyway, to sum it up, languages that compile to intermediate formats (managed languages) can generally be decompiled back to something closer to the original more easily than those that aren’t, but this isn’t a hard and fast rule and depends upon the purpose the intermediate language than the fact that it is an intermediate language.</p>

CC BY-SA 4.0
2024-02-26T01:47:02.150Z
2024-02-26T01:47:02.150Z
jmoreno
<p>Any compiler converts some kind of code into other kinds of code.  Like C to machine code or Rust to C.  You typically move closer to what a machine can actually execute.</p>
<p>Java has <em>two</em> compilation steps.  One from humanly readable source into a high level byte code, and one from that byte code into actual machine code (the latter happens on runtime so is rarely visible).   It was decided back then to put the efforts on the second step which is now paying off.  Even though Java was mocked back then for being slow, Suns focus on <em>correctness</em> and <em>robustness</em> is now a major reason that Java is a frequent choice of what runs on the servers even though .NET Core is catching up.  As Java is not slow anymore, Oracle is adding functionality that allows you to execute the humanly readable source code directly at runtime!</p>
<p>If you as a  Java programmer do not want your code to be reverse engineerable, you can choose other forms.   There are obfuscators like proguard which changes things to make it hard, and compilers like Excelsior JET and GraalVM that can produce the final machine code ahead of time.  Typically in my opinion there is rarely a need, as if you are in a situation where this matters there are usually already contracts in place that cover the way you can use the code.</p>

CC BY-SA 4.0
2024-02-25T09:25:07.773Z
2024-02-25T09:25:07.773Z
Thorbjørn Ravn Andersen
<blockquote>
<p>A computer language, being decompilable and not needing a runtime engine, is this possible?</p>
</blockquote>
<p>Yes. In the stage where the compiler creates the assembly (or later machine code), it could easily inject special bytes which are skipped during execution, but encode the original source material in a format that makes reconstructing the source code possible. As a crass thought experiment, it could simply append the original source code as-is within the executable in some kind of data structure that is not actually executed.</p>
<p>This would of course take a <em>lot</em> of effort (not necessarily during runtime, but to come up with a sensible, efficient encoding scheme).</p>
<p>How to inject arbitrary bytes into an executable is a minor implementation detail, but a trivial way would be to just put them in there and skip them through a simple (relative) JMP instruction, depending on what the target architecture offers.</p>
<blockquote>
<p>A computer language, being launched using a runtime engine but not being decompilable, would this make sense?</p>
</blockquote>
<p>Yes, for sure. It would not only make sense in whether it would be technically possible, but also for example to make it harder to decompile (e.g. obfuscation etc.). In this case you would do the opposite of what I described above, you would <em>skip</em> injecting some kind of meta information into the bytecode. Then decompiling said bytecode would be as difficult or easy as decompiling &quot;actual&quot; machine code, and would require deep knowledge about how the compiler works - even if is goes heavy on the optimization.</p>
<p>N.B. there is not really that much difference between a native compiler targeting a CPU directly, and a bytecode compiler. The bytecode is simply the &quot;machine code&quot; of the runtime interpreter. Yes, the details are of course wildly different (since the runtime and the compiler are probably designed and developed in tandem, and can be targeted as a much more high-level architecture than a CPU, many things can be designed in that would be tough for a physical CPU architecture - for example a class system, the bytecode stored in a tree instead of sequential OP codes etc.), but there is no fundamental difference regarding decompilation.</p>

CC BY-SA 4.0
2024-02-23T13:34:16.550Z
2024-02-23T13:34:16.550Z
AnoE
CC BY-SA 4.0
2024-02-28T20:36:16.120Z
The "special bytes" approach doesn't even need a complicated data structure. Common executable file formats tend to ignore any junk data past the end of their structures, so the source code can simply be appended to the target file. Even better, if you put the entire source code in a ZIP file first, extracting the source code becomes very easy, because the ZIP format works "back to front" and such is extractable even with unreadable junk (aka the actual executable) prepended to it! I learned this works from [LÖVE](https://love2d.org/), where games were generally distributed in "fused" form.
Jasmijn
CC BY-SA 4.0
2024-02-29T08:33:31.963Z
Very correct, @Jasmijn, thanks for the thoughts!
AnoE
<p>The main reason why Java (and in theory C# as well) is more easily decompilable than languages which get compiled to native machine code is that Java and C# both provide a feature which makes this easier for decompilers: <strong>Reflection</strong>.</p>
<p>Reflection makes it necessary that the types in - let's say Java - binaries provide all the metadata about their fields, method names, method signatures, interfaces, access modifiers and so on. Hence, the type structure cannot easily be &quot;optimized away&quot; at the bytecode level, and a decompiler can utilize this structure.</p>
<p>Of course, though their binaries are not &quot;aggressively optimized&quot;, Java and C# programs can be executed quite efficiently. That's because they are usually processed by efficient Just-In-Time compilers - which are part of every runtime. Note Reflection does not require the compiler to keep code comments in the binary, so this part of the source code is usually lost after compiling to byte code and cannot be reconstructed.</p>
<p>So in short, Reflection makes it likely that the compiler will produce binaries which are &quot;not-too-optimized&quot;, in such a way that they can be still decompiled, and a runtime with a JIT is then required to make those programs work efficiently. Of course, this design of a language implementation is not mandatory, but seen frequently today.</p>
<p>Would it be possible to have a language &quot;being decompilable&quot; and not needing a runtime engine? Sure, that's simple. As a thought experiment, someone could create a C or C++ compiler which adds enough metadata into an executable binary to make decompilation easy. It could, for example, insert the whole source code into an unused data section.</p>
<p>Indeed, most modern compilers (not just C or C++) <strong>can</strong> actually add such metadata to their output - when you compile the code for the purpose of source level debugging (inside or alongside to the compiled binary). That is, however, a feature of the compiler/debugging environment, not a property of the language, and this feature is often used in combination with the disabling of certain optimizations which would defeat decompilation.</p>
<p>Now to your second question about programming languages / ecosystems which require a run-time but are not as easily decompilable. That's also not just theory: you may heave heard of tools like Obfuscators for Java and C#. Though not perfect, they can make it pretty hard to decompile byte code into a form a human can efficiently work with. Those tools, however, will often conflict with the use of Reflection - which is IMHO not very astonishing.</p>
<p>There are also older language implementations like UCSD Pascal, where the compiler created byte code (known as P-Code), so a run-time system was definitely necessary. Still, AFAIK UCSD Pascal did not provide Reflection, hence I would not expect a decompiler for that language to work as well as a modern decompiler for Java.</p>

CC BY-SA 4.0
2024-02-22T15:24:21.660Z
2024-11-04T12:28:06.540Z
2024-11-04T12:28:06.540Z
Doc Brown
CC BY-SA 4.0
2024-02-22T18:10:56.030Z
Another factor for Java at least is the debugging information that is typically included in the byte code.  By default, line numbers and source file information is included.
JimmyJames
CC BY-SA 4.0
2024-02-23T09:51:07.057Z
It's the runtime reflection that's an issue. Compile time reflection would of course have less of that problem.
Aykhan Hagverdili
CC BY-SA 4.0
2024-02-23T10:09:47.497Z
@AykhanHagverdili: Indeed. Specifically, while compile-time reflection can be used to generate information used to reflect at run-time -- think serialization -- _only_ the information that is strictly necessary -- only fields, for example, and only for those classes which opted in -- would be encoded, resulting in an overall decrease of metadata.
Matthieu M.
CC BY-SA 4.0
2024-02-23T18:17:42.293Z
On Unix type environments, there is a command called "strip" and its function is to remove the debugging metadata from executables. It was used in the past where space and time were at a premium.
Walter
CC BY-SA 4.0
2024-02-26T01:57:51.310Z
You should be able to compile to machine code with complete debugging stabs and full optimization via `gcc -g -O3`.
tchrist
<p>Your specific questions are not really answerable, because your question contains a number of assumptions that are not true (or at least, not entirely accurate).</p>
<blockquote>
<p>the compilation process was reversible: Java compiled binaries can be decompiled!</p>
</blockquote>
<p>Yes, Java class files can be decompiled. But the process is not reversible - you are not guaranteed to get back the same Java code as you started with if you go through a compile -&gt; decompile loop.</p>
<blockquote>
<p>A computer language, being decompilable and not needing a runtime engine, is this possible?</p>
</blockquote>
<p>This depends what you mean by &quot;decompilable&quot;. If you mean &quot;definitely get back the original source code&quot;, then no - but then that's not possible for Java or to a very real extent any other compiled language either. However, there are plenty of tools which will make a good attempt at decompiling your native code binaries - e.g. <a href="https://ghidra-sre.org/" rel="noreferrer">Ghidra</a>.</p>
<blockquote>
<p>A computer language, being launched using a runtime engine but not being decompilable, would this make sense?</p>
</blockquote>
<p>Again depends what you mean by &quot;decompilable&quot;. There is theoretically no difference between x64 opcodes and JVM opcodes - they are both just instructions that specify how to execute a program. Sure, you <em>typically</em> are executing x64 opcodes on an actual physical CPU and JVM opcodes in some kind of runtime environment, but there's nothing that stops you having an x64 runtime environment or a physical JVM CPU. If I've got the opcodes, I can attempt to decompile it to human-readable source code. I might not do it very well, but fundamentally the process doesn't change based on the instruction set you give me.</p>

CC BY-SA 4.0
2024-02-22T13:12:33.650Z
2024-02-22T13:12:33.650Z
Philip Kendall
# What's the relation between a language being managed and its compiler being reversible?
Posted by: username_0 on 2024-02-22
As a starting developer, I worked with Pascal and Delphi. Later on, I came in contact with C++ and Visual Basic. All those are native languages, which means that their compiled binaries were executables, dynamic libraries (`*.dll` or `*.so`), to be launched on the underlying platform (Windows, UNIX, ...) and the process of compiling was not reversible.

Later on, I heard about Java. A strange language, in the sense that it does not get compiled into binaries which run directly on the platform, but on some "runtime engine", and those could run the same compiled Java sources (so-called bytecode) on whatever platform. Another weird thing is that the compilation process was reversible: Java compiled binaries can be decompiled!

Some years ago, I worked (for a very short and difficult period) for a firm, where programming was done in ABL (or Progress, as they called it). That language had similar properties as Java: working in a runtime environment and being decompilable.

Just out of curiosity, I wonder if both properties are linked, hence these two questions:

1. Is it possible to have a computer language, being both decompilable **and** not needing a runtime engine?
2. How about a computer language, launched using a runtime engine but not being decompilable, would this make sense?

P.S.1 the ideal tag for this question is "language-lawyer", but this tag only exists on StackOverflow. Is this the right place for this question or do I need to migrate it to StackOverflow?  
P.S.2 currently I'm working with C#. This compiles to executables or DLLs, a "decompiler" (JetBrains) exists, but the results are very disappointing, hence my first question.

**Edit**  
This is how I understand a compilation being reversible:
Compiling source code is something which is done in several steps, some of those are reversible, some are not, and apparently the first steps are reversible. Binary code being decompilable means that only the first (reversible) steps have been executed. This means that decompilable compilers only go up to a certain depth.  
Managed code also means that the compilation does not go up to the final depth.  
Hence my (apparently wrong) idea:  
*Would there be a link between "decompilable depth" and "managed depth"?*
**Tags:** compilers language-comparison
> **Comments:**
> **username_1**: "apparently the first steps are reversible" Could you give a reference to where you read this? Even what is typically the very first stage of compliation (tokenizing the input) is not reversible as it will often throw away things like insignificant whitespace etc.  
> **username_2**: This question seems more appropriate for [langdev.se].  
> **username_3**: Not all pascals compiled to machine code. Some of the early pascals for microcomputers  (UCSD( compiled to pcode. This was then run by a pcode engine at runtime. Compiling to machine code or byte code is choice that can made by implementers. It is not fixed per language.  
> **username_4**: Information is typically thrown away in the compilation process because it is not needed.  Variable names, comments, compiler directives.  If you want to reverse the process you need to save it _somewhere_ - frequently this is called debug information.  
---
## 5 answers
### Answer by username_8 on 2024-02-22. Score: 51
The main reason why Java (and in theory C# as well) is more easily decompilable than languages which get compiled to native machine code is that Java and C# both provide a feature which makes this easier for decompilers: **Reflection**.

Reflection makes it necessary that the types in - let's say Java - binaries provide all the metadata about their fields, method names, method signatures, interfaces, access modifiers and so on. Hence, the type structure cannot easily be "optimized away" at the bytecode level, and a decompiler can utilize this structure.

Of course, though their binaries are not "aggressively optimized", Java and C# programs can be executed quite efficiently. That's because they are usually processed by efficient Just-In-Time compilers - which are part of every runtime. Note Reflection does not require the compiler to keep code comments in the binary, so this part of the source code is usually lost after compiling to byte code and cannot be reconstructed.

So in short, Reflection makes it likely that the compiler will produce binaries which are "not-too-optimized", in such a way that they can be still decompiled, and a runtime with a JIT is then required to make those programs work efficiently. Of course, this design of a language implementation is not mandatory, but seen frequently today.

Would it be possible to have a language "being decompilable" and not needing a runtime engine? Sure, that's simple. As a thought experiment, someone could create a C or C++ compiler which adds enough metadata into an executable binary to make decompilation easy. It could, for example, insert the whole source code into an unused data section.

Indeed, most modern compilers (not just C or C++) **can** actually add such metadata to their output - when you compile the code for the purpose of source level debugging (inside or alongside to the compiled binary). That is, however, a feature of the compiler/debugging environment, not a property of the language, and this feature is often used in combination with the disabling of certain optimizations which would defeat decompilation.

Now to your second question about programming languages / ecosystems which require a run-time but are not as easily decompilable. That's also not just theory: you may heave heard of tools like Obfuscators for Java and C#. Though not perfect, they can make it pretty hard to decompile byte code into a form a human can efficiently work with. Those tools, however, will often conflict with the use of Reflection - which is IMHO not very astonishing.

There are also older language implementations like UCSD Pascal, where the compiler created byte code (known as P-Code), so a run-time system was definitely necessary. Still, AFAIK UCSD Pascal did not provide Reflection, hence I would not expect a decompiler for that language to work as well as a modern decompiler for Java.
> **Comments:**
> **username_9** (2024-02-22): Another factor for Java at least is the debugging information that is typically included in the byte code.  By default, line numbers and source file information is included.  
> **username_10** (2024-02-23): It's the runtime reflection that's an issue. Compile time reflection would of course have less of that problem.  
> **username_11** (2024-02-23): @AykhanHagverdili: Indeed. Specifically, while compile-time reflection can be used to generate information used to reflect at run-time -- think serialization -- _only_ the information that is strictly necessary -- only fields, for example, and only for those classes which opted in -- would be encoded, resulting in an overall decrease of metadata.  
> **username_3** (2024-02-23): On Unix type environments, there is a command called "strip" and its function is to remove the debugging metadata from executables. It was used in the past where space and time were at a premium.  
> **username_12** (2024-02-26): You should be able to compile to machine code with complete debugging stabs and full optimization via `gcc -g -O3`.  
---
### Answer by username_1 on 2024-02-22. Score: 14
Your specific questions are not really answerable, because your question contains a number of assumptions that are not true (or at least, not entirely accurate).

> the compilation process was reversible: Java compiled binaries can be decompiled!

Yes, Java class files can be decompiled. But the process is not reversible - you are not guaranteed to get back the same Java code as you started with if you go through a compile -> decompile loop.

> A computer language, being decompilable and not needing a runtime engine, is this possible?

This depends what you mean by "decompilable". If you mean "definitely get back the original source code", then no - but then that's not possible for Java or to a very real extent any other compiled language either. However, there are plenty of tools which will make a good attempt at decompiling your native code binaries - e.g. [Ghidra](https://ghidra-sre.org/).

> A computer language, being launched using a runtime engine but not being decompilable, would this make sense?

Again depends what you mean by "decompilable". There is theoretically no difference between x64 opcodes and JVM opcodes - they are both just instructions that specify how to execute a program. Sure, you *typically* are executing x64 opcodes on an actual physical CPU and JVM opcodes in some kind of runtime environment, but there's nothing that stops you having an x64 runtime environment or a physical JVM CPU. If I've got the opcodes, I can attempt to decompile it to human-readable source code. I might not do it very well, but fundamentally the process doesn't change based on the instruction set you give me.
---
### Answer by username_5 on 2024-02-26. Score: 2
First you need a good understanding of the difference between compiled and interpreted. This is not a matter of language, but of distribution and process. If what is distributed and processed (executed) is what the developer wrote, then it’s interpreted. If what is distributed has been transformed (ignoring stripping of white space and comments and possibly obscuration), it’s compiled.

With interpreted distribution, there is nothing to decompile, what is available is the original.

With compilation, the transformation is almost certainly going to be lossy, ie you can’t go back and forth between the two without loss because that’s not a design goal and adding the ability to do so would generally be a waste — you are looking for the new format, not to allow someone else to get the source you already have.

That said, when the destination is an intermediate format, one which is itself expected to be compiled/interpreted , it tends to keep a similar structure and the same function names. Global optimization and inline methods are generally not done. All of which means that the compiled code is still somewhat similar to the original code.

Despite this similar structure and at least some names being retained, it’s still intended to be a one way process, and is going to be lossy, just not as lossy as would be the case if it was being compiled to a machine code.

One other point, sometimes compilers generate debugging information that allows associating the compiled code back to the original source code.

Anyway, to sum it up, languages that compile to intermediate formats (managed languages) can generally be decompiled back to something closer to the original more easily than those that aren’t, but this isn’t a hard and fast rule and depends upon the purpose the intermediate language than the fact that it is an intermediate language.
---
### Answer by username_4 on 2024-02-25. Score: 2
Any compiler converts some kind of code into other kinds of code. Like C to machine code or Rust to C. You typically move closer to what a machine can actually execute.

Java has *two* compilation steps. One from humanly readable source into a high level byte code, and one from that byte code into actual machine code (the latter happens on runtime so is rarely visible). It was decided back then to put the efforts on the second step which is now paying off. Even though Java was mocked back then for being slow, Suns focus on *correctness* and *robustness* is now a major reason that Java is a frequent choice of what runs on the servers even though .NET Core is catching up. As Java is not slow anymore, Oracle is adding functionality that allows you to execute the humanly readable source code directly at runtime!

If you as a Java programmer do not want your code to be reverse engineerable, you can choose other forms. There are obfuscators like proguard which changes things to make it hard, and compilers like Excelsior JET and GraalVM that can produce the final machine code ahead of time. Typically in my opinion there is rarely a need, as if you are in a situation where this matters there are usually already contracts in place that cover the way you can use the code.
---
### Answer by username_6 on 2024-02-23. Score: 1
> A computer language, being decompilable and not needing a runtime engine, is this possible?

Yes. In the stage where the compiler creates the assembly (or later machine code), it could easily inject special bytes which are skipped during execution, but encode the original source material in a format that makes reconstructing the source code possible. As a crass thought experiment, it could simply append the original source code as-is within the executable in some kind of data structure that is not actually executed.

This would of course take a *lot* of effort (not necessarily during runtime, but to come up with a sensible, efficient encoding scheme).

How to inject arbitrary bytes into an executable is a minor implementation detail, but a trivial way would be to just put them in there and skip them through a simple (relative) JMP instruction, depending on what the target architecture offers.

> A computer language, being launched using a runtime engine but not being decompilable, would this make sense?

Yes, for sure. It would not only make sense in whether it would be technically possible, but also for example to make it harder to decompile (e.g. obfuscation etc.). In this case you would do the opposite of what I described above, you would *skip* injecting some kind of meta information into the bytecode. Then decompiling said bytecode would be as difficult or easy as decompiling "actual" machine code, and would require deep knowledge about how the compiler works - even if is goes heavy on the optimization.

N.B. there is not really that much difference between a native compiler targeting a CPU directly, and a bytecode compiler. The bytecode is simply the "machine code" of the runtime interpreter. Yes, the details are of course wildly different (since the runtime and the compiler are probably designed and developed in tandem, and can be targeted as a much more high-level architecture than a CPU, many things can be designed in that would be tough for a physical CPU architecture - for example a class system, the bytecode stored in a tree instead of sequential OP codes etc.), but there is no fundamental difference regarding decompilation.
> **Comments:**
> **username_7** (2024-02-28): The "special bytes" approach doesn't even need a complicated data structure. Common executable file formats tend to ignore any junk data past the end of their structures, so the source code can simply be appended to the target file. Even better, if you put the entire source code in a ZIP file first, extracting the source code becomes very easy, because the ZIP format works "back to front" and such is extractable even with unreadable junk (aka the actual executable) prepended to it! I learned this works from [LÖVE](https://love2d.org/), where games were generally distributed in "fused" form.  
> **username_6** (2024-02-29): Very correct, @Jasmijn, thanks for the thoughts!  
---
