<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Tal's IO]]></title><description><![CDATA[Thoughts and ideas on software development.]]></description><link>https://tals.io</link><generator>RSS for Node</generator><lastBuildDate>Wed, 15 Apr 2026 04:07:30 GMT</lastBuildDate><atom:link href="https://tals.io/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[The Convenience of a Type System]]></title><description><![CDATA[Context: Exploring the usefulness of type systems in the development of software. This is not a 
programming languages deep dive, so terminology might be custom-fitted for this discussion.
I do not try to define terms in the absolute, but I aim to ex...]]></description><link>https://tals.io/the-convenience-of-a-type-system</link><guid isPermaLink="true">https://tals.io/the-convenience-of-a-type-system</guid><category><![CDATA[software development]]></category><dc:creator><![CDATA[Tal Shani]]></dc:creator><pubDate>Thu, 06 Feb 2025 16:33:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738851061460/8700861b-b654-4cfe-b9bf-edbd711eca14.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>Context</strong>: Exploring the usefulness of type systems in the development of software. This is not a 
programming languages deep dive, so terminology might be custom-fitted for this discussion.</p>
<p>I do not try to define terms in the absolute, but I aim to explore what type systems give us as developers, 
and the difference between various kinds. Trying to pinpoint why it is useful, when and how.</p>
</blockquote>
<h3 id="heading-what-is-a-type-system">What is a Type System?</h3>
<p>Type systems are the mathematics and rules used <em>mostly</em> by programming languages to check the simple statement which is also a <strong>type check</strong>:</p>
<blockquote>
<p>"Is A assignable to B?" - Where A and B are any types.</p>
</blockquote>
<h2 id="heading-runtime-vs-compile-time">Runtime vs. Compile Time</h2>
<p>When writing code, we use text written in a programming language. The machine can't really
do anything with that, so we use a compiler to make it "machine understandable". This machine
code is our binary which we execute and create a runtime environment for our program to run in.</p>
<p>Narrowing down on this flow, we can draw the following develop-run cycle</p>
<blockquote>
<p>source code -&gt; compilation -&gt; code gen: binary -&gt; execution: runtime</p>
</blockquote>
<p>There are two popular places where we can place type checks: "compilation" and "runtime".
In each check point we can also decide how to react when this check fails. 
We could decide that this check is not so important, and we can continue, or we must stop the cycle and report to the developer.</p>
<h3 id="heading-runtime-failure">Runtime failure</h3>
<p>Starting from the easy check point. If a type check fails in an already executing application, 
the system breaks. This might be recoverable, but any "Is A assignable to B?" check that fails
on runtime, must be handled or the program cannot continue running.</p>
<h3 id="heading-compile-time-failure">Compile time failure</h3>
<p>Failure of the type-check in compilation requires a bit more of our analysis.</p>
<p>Compilation phase is running on a developer machine, which is usually strong. It also running in an environment which is usually without any resource regime. This privilege allow us to run far better checks.</p>
<p>Some languages are "strongly typed" and we consider them compiled languages.
In these languages, if we fail the type-check at compile time, we must stop and we cannot generate a binary. This for example happens in the following Java snippet</p>
<pre><code class="lang-java">String x = <span class="hljs-string">"hello"</span>;
<span class="hljs-keyword">int</span> y = (<span class="hljs-keyword">int</span>) x; <span class="hljs-comment">// Casting which the compiler can prove is wrong, so it will fail here</span>
</code></pre>
<p>In Java's case, the type checks the compiler is doing, is a requirement to finish the compilation step. 
The consistent type information that the compiler check for and verify,
is a critical piece in the puzzle which the compiler is trying to solve in order generate the binary.</p>
<p>Contrary to that, there are languages where the compilation phase doe not require the type checks to pass. 
For example - Typescript adds a type system on top of it's target language, Javascript. The runtime type system of Javascript is decoupled (but aligned) with Typescript's.
This makes the type-check a non-requirement for the compilation phase, and even when we fail, we can still continue with the dev-run cycle and generate a "binary".</p>
<p>Take for example the following snippet in Typescript, that when we type check it, it will fail</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">let</span> x:<span class="hljs-built_in">string</span> = <span class="hljs-number">5</span>
</code></pre>
<p>In this case, our compiler will complain that "type 'number' is not assignable to type 'string'". We can still generate the target Javascript code for it, and it will be valid javascript which will be evaluated successfully.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> x = <span class="hljs-number">5</span>
</code></pre>
<p>Stripping the type information makes this a valid javascript, so Typescript in compilation phase just 
need to strip type information, and then we can continue to the runtime phase with no issue.</p>
<p>We can summarize the 3 modes of type systems:</p>
<ol>
<li>Compile Time - A strongly typed language which has a type system in runtime and the compiler must make sure we pass type check at compile time.</li>
<li>Only Runtime - There is no check at compile time, types exist only in compile time, and they are implemented as checks in the runtime itself.</li>
<li>Optional Compile Time - Usually on top of Runtime system, we overlay another type system at compile time, that can be used to check the program.</li>
</ol>
<h2 id="heading-type-checks-as-quality-feedback">Type Checks as quality feedback</h2>
<p>Compile time type system, optional or not, are best looked at as cheap tests. 
They are very quick to add, clear to the reader and easy to reason about.
These tests are so cheap, that you do not need to run a test runner to test them,
the IDE (development environment) will check them for you in the background as you type.</p>
<p>In optional systems, it is even more so - The optionality of the checks allow us to play and prototype rapidly with or without types, break them and still execute the program. We can incrementally add type, refine and iterate.</p>
<p>Let's take a look at myPy in python for example:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_2</span>(<span class="hljs-params">num</span>):</span>
    <span class="hljs-keyword">return</span> num + <span class="hljs-number">2</span>
print(add_2(<span class="hljs-number">1</span>))
</code></pre>
<p>This program just add <code>2</code> to every number we pass in. 
The <code>num</code> argument has no assertion, no requirement from the world. It is just requiring that the <code>add_2</code> function will be called with 1 argument.</p>
<p>Using mypy, we can add a type hint:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_2</span>(<span class="hljs-params">num:int</span>):</span> // &lt;- Added type hint
    <span class="hljs-keyword">return</span> num + <span class="hljs-number">2</span>
print(add_2(<span class="hljs-number">1</span>))
</code></pre>
<p>Which increased the requirements of the code, not for execution but for testing (remember that now type checks are optional so we treat them as part of our test phase). 
Running mypy command line tool, will check that every call to <code>add_2</code> passes a single argument which can be proved is an <code>int</code>.</p>
<p>Lets look at another example:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_2</span>(<span class="hljs-params">num:int</span>):</span>
    <span class="hljs-keyword">return</span> num + <span class="hljs-number">2</span>
print(add_2(<span class="hljs-string">"magic"</span>)) // Note here we <span class="hljs-keyword">pass</span> a string
</code></pre>
<p>We can still run the above python code even though it does not pass mypy type check.
At runtime, when executed, the code will fail at runtime saying that the 
"operator <code>+</code> is not supported for <code>str</code> and <code>int</code>".</p>
<h2 id="heading-summary">Summary</h2>
<p>For a first post this is becoming too long so I will wrap it up here.</p>
<p>The key takeaway from this is that types can be very easy to introduce and improve our code quality.</p>
<p>Incrementally we can add types to our code, which like unit tests increase the amount of claims or assertions we have on our system. 
Unlike unit-tests, types are far easier to maintain, they have little overhead and even contribute to 
in-context code readability.</p>
<p>I hope you find this useful and it made you think about types a bit differently.</p>
<p>In the future I wish to explore what other checks we can add to the development flow that combine the easiness and robustness of asserting with a type system.</p>
]]></content:encoded></item></channel></rss>