<h2>JavaScript Interop</h2>
<p>
+ Onyx now has a proper JavaScript interop layer, which makes using Onyx from JavaScript easier than ever.
+ This interop comes in two parts: the <code>#js</code> directive and the <code>code.js</code> package.
+</p>
+<p>
+ The <code>#js</code> directive is used to include JS source code in the project.
+ When any <code>#js</code> directive is encountered in the code, an additional JS file will be generated by the compiler.
+</p>
+<p>
+ <code>#js</code> has the following syntax.
+</p>
+
+<pre class="hljs"><code class="language-onyx">// Include JS from string literal
+#js """
+ // Raw JS source code here
+"""
+
+// Inlcude JS from file
+#js #file "./source.js"
+
+// Specify order of JS partial with an int literal
+// Lower numbers are inserted first
+#js 100 #file "./source.js"
+</code></pre>
+
+<p>
+ This by itself does not help you interop with JavaScript, but it is required to have the compiler
+ also generate the additional source code to make your project work. In fact, you may never have to
+ use it directly, as it is more intended for library authors.
+</p>
+<p>
+ To actually interop with JS, there is now the <a href="https://docs.onyxlang.io/packages/core.js"><code>core.js</code> package</a>. This package was inspired
+ by Go's <a href="https://pkg.go.dev/syscall/js"><code>syscall/js</code></a>, which provides a thin abstraction
+ layer over JavaScript's common operations, like function calls, <code>new</code> and <code>obj["foo"]</code>.
+</p>
+<p>
+ Here is a simple example/demo that creates a button on the page, and when it is clicked, alerts with a message.
</p>
+<pre class="hljs"><code class="language-onyx">use core.js
+
+main :: () {
+ document := js.Global->get("document");
+
+ button := document->call("createElement", "button");
+ button->set("innerHTML", "Click me!");
+ button->call("addEventListener", js.func((this, args) => {
+ js.Global->call("alert", "Hello from Onyx!");
+
+ return js.Undefined;
+ }));
+
+ document->get("body")->call("appendChild", button);
+}
+</code></pre>
+
+<p>
+ To use this in on your page, you can use the following JavaScript.
+ It will load the JavaScript file generated by the compiler, and use the
+ <code>Onyx</code> class to load and link the WebAssembly binary, from
+ which you can call <code>start</code> to start the program.
+</p>
+
+<pre class="hljs"><code class="language-html"><script type="module">
+ import Onyx from "/out.wasm.js"
+ (await Onyx.load("/out.wasm")).start()
+</script>
+</code></pre>
+
+<p>
+ Finally, compile the code with the <code>-r js</code> flag.
+</p>
+
+<pre class="hljs"><code class="language-sh">onyx build -r js program.onyx
+</code></pre>
+
+<p>
+ While this is a very low-level interface to JavaScript, it does enable Onyx
+ to be used in a whole new class of applications on the web. More auxillary packages
+ can be developed to provide specialized APIs for comming things such as the DOM, WebSockets,
+ or <a href="https://github.com/onyx-lang/pkg-webgl2">WebGL</a>.
+</p>
+
+
<h2>Deprecation of <code>#inject</code></h2>
<p>
+ As I have written more Onyx code, I have realized I use <code>#inject</code> <em>all the time</em>.
+ It has become so ubiquitous in my code that I experimented with extending the parser so the <code>#inject</code>
+ directive would not be required, and I loved it. For this reason, <code>#inject</code> is being deprecated.
+</p>
+
+<p>
+ Now you can simply add a new scoped binding like you would with any other binding.
+</p>
+
+<pre class="hljs"><code class="language-onyx">Dog :: struct {}
+
+// No #inject here!
+Dog.speak :: (d: &Dog) {
+ println("Bark!");
+}
+</code></pre>
+
+<p>
+ Note that without the <code>#inject</code> keyword, there is no equivalent of the
+ <a href="https://docs.onyxlang.io/book/directives/inject.html">block form</a>.
+ Each scoped binding must be specified individually on a new line. I prefer this,
+ as it prevents what I consider unnecessary indentation.
+</p>
+
+<p>
+ In a future release yet to be determined, the <code>#inject</code> directive will be
+ removed entirely, but for now all programs with it will still compile.
</p>
<h2><code>Array</code> and <code>Slice</code> structures</h2>
<p>
+ There has been a long running inconsistency in Onyx where dynamic arrays and slices were
+ not like other types, in that they could not have methods and required you to use functions
+ defined in the standard library from the <code>core.array</code> and <code>core.slice</code> packages.
+</p>
+<p>
+ This has finally been addressed with the addition of the <code>Array</code> and <code>Slice</code> builtin
+ structures. They serve as "namespaces" for methods in dynamics arrays and slices respectively.
+</p>
+<p>
+ The core library now defines all dynamic array functionality as methods on <code>Array</code> and all
+ slice functionality as methods on <code>Slice</code>. All existing definitions from <code>core.array</code>
+ and <code>core.slice</code> still exist to maintain backwards compatibility, but the new locations of
+ these definitions should be preferred.
+</p>
+
+<pre class="hljs"><code class="language-onyx">// No need to use anything :)
+
+main :: () {
+ arr := make([..] i32);
+
+ for i in 0 .. 10 {
+ // Use as a method.
+ arr->push(i);
+
+ // Use a static function on Array.
+ Array.push(&arr, i);
+ }
+
+ logf(.Info, "Array: {}", arr);
+}
+</code></pre>
+
+<p>
+ These changes represent a larger move towards standardizing the pattern that associated procedures
+ for a type are defined as bindings within the type's scope. That way, the consumer of library can either choose
+ to use the procedure as a "method", i.e. <code>x->proc(y)</code>, or as a standard procedure prefix with the type
+ name, i.e. <code>X.proc(&x, y)</code>. When the procedure lives in a package, they are forced to use the standard
+ procedure syntax.
</p>
<h2>Minor syntax additions</h2>
+
+<h3>Auto-disposing locals</h3>
+<p>
+ A very common pattern in Onyx is to create/allocate a resource, then <code>defer</code> the release/free of the resource
+ on the next line. As an experiment, there is now a way to automate the freeing of a resource, called <em>auto-disposing locals</em> (<em>I'm still working on the name...</em>).
+</p>
<p>
+ To mark a local variable as auto-disposing, simply place the <code>use</code> keyword in front of its declaration.
+</p>
+<pre class="hljs"><code class="language-onyx">main :: () {
+ use arr := make([..] i32);
+}
+</code></pre>
+<p>
+ This code will automatically insert a deferred call to the builtin overloaded procedure <code>__dispose_used_local</code>, which
+ can be overloaded to define how to dispose of the resource.
+ It has the <code>delete</code> procedure in the list of overloads, so anything you can call <code>delete</code> on,
+ you can <code>use</code>. This is the equivalent code without <code>use</code>.
+</p>
+<pre class="hljs"><code class="language-onyx">main :: () {
+ arr := make([..] i32);
+ defer __dispose_used_local(&arr);
+}
+</code></pre>
+<p>
+ As stated before, this feature is experimental and probably not perfect yet, but after using the
+ <a href="https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/using"><code>using</code> keyword in C#</a>, I wanted to have something similar in Onyx.
</p>
<h3>Inclusive Range (<code>..=</code>)</h3>
<p>
+ As a small convenience, there is now an inclusive range operator, <code>..=</code>.
+ This operator is <a href="https://github.com/onyx-lang/onyx/blob/297cadce463fabf7ac68fa602b89d879e2892422/compiler/src/checker.c#L1965">equivalent</a> to <code>x .. (y + 1)</code>.
</p>
-
-<h3><code>range64</code></h3>
<p>
+ While a small addition, it cleans up a lot of ugly <code>+ 1</code>s around many codebases.
</p>
<h2>Revamped CLI</h2>
<p>
+ The command-line interface got a major face-lift in this update.
+ It features new shorthand for common commands like <code>build</code> and <code>run</code>.
+ It also includes <em>colors</em> on Linux and MacOS.
+ This might not seem worth mentioning but these little improvements add to the overall developer
+ experience and make Onyx <em>feel</em> more polished and production-ready.
</p>
-<pre class="hljs"><code class="language-onyx">
+<h2>Updating</h2>
+<p>
+ To update to the newest version of Onyx simply use the same install script found on the homepage.
+ It will automatically detect your previous install and will override it with the new version.
+</p>
+<pre class="hljs"><code class="language-sh">$ sh <(curl https://get.onyxlang.io -sSfL)
</code></pre>
-
+<p>
+ <em>In the future, you will be able to use the <code>onyx self-upgrade</code> command!</em>
+</p>
<h2>Full Changelog</h2>
<h3>Additions</h3>
</ul>
<h3>Removals</h3>
-<p><em>Nothing to mention here!</em></p>
+<ul>
+ <li><code>os.with_file</code></li>
+</ul>
<h3>Changes</h3>
<ul>
a.link-button:hover {
/* top: -6px; */
- box-shadow: 0 6px 15px 8px rgba(200, 200, 230, 0.2);
+ /* box-shadow: 0 6px 15px 8px rgba(200, 200, 230, 0.2); */
cursor: pointer;
}
font-size: 16pt;
background-color: var(--secondary);
color: var(--text);
- box-shadow: 0px 3px 12px 2px rgba(200, 200, 230, 0.2);
+ /* box-shadow: 0px 3px 12px 2px rgba(200, 200, 230, 0.2); */
position: relative;
top: 0;
transition: all 0.2s;
a.cta-button:hover {
/* top: -6px; */
- box-shadow: 0 6px 15px 8px rgba(200, 200, 230, 0.2);
+ /* box-shadow: 0 6px 15px 8px rgba(200, 200, 230, 0.2); */
cursor: pointer;
}
.container > p {
margin-top: 20px;
+ line-height: 1.5rem;
}
.container ul, .container ol {
.container.card > * {
background: linear-gradient(135deg, var(--background), var(--accent-background));
- box-shadow: 0px 3px 16px 8px rgba(150, 150, 230, 0.2);
+ /* box-shadow: 0px 3px 16px 8px rgba(150, 150, 230, 0.2); */
border-radius: 8px;
border: 1px solid var(--primary);
padding: 8px;
navbar a span:hover {
cursor: pointer;
background-color: var(--header-accent);
- box-shadow: 0px 3px 16px 8px rgba(150, 150, 230, 0.2);
+ /* box-shadow: 0px 3px 16px 8px rgba(150, 150, 230, 0.2); */
}
navbar a:visited {
background: linear-gradient(135deg, var(--background), var(--accent-background));
border: 1px solid var(--primary);
border-radius: 6px;
- box-shadow: 0px 3px 16px 8px rgba(150, 150, 230, 0.2);
+ /* box-shadow: 0px 3px 16px 8px rgba(150, 150, 230, 0.2); */
padding: 8px;
display: block;
overflow-y: auto;
border: 1px solid var(--accent);
width: 100%;
background: linear-gradient(135deg, #000, var(--accent-background));
- box-shadow: 0px 3px 16px 8px rgba(150, 150, 230, 0.2);
+ /* box-shadow: 0px 3px 16px 8px rgba(150, 150, 230, 0.2); */
margin-top: 24px !important;
}