Jekyll2020-01-31T03:14:40+00:00https://ethanbell.me/feed.xmlA Clean, Well-Lighted PlaceEthan Bell's BlogEthan Belleb@ethanbell.meAbstract Data Types: The Other ADTs2019-07-08T00:00:00+00:002019-07-08T00:00:00+00:00https://ethanbell.me/abstract-data-types<p>Abstract Data Types are a crucial construct in everyday programming. They effectively constitute all types which values might have. For the sake of brevity, I will refer to Abstract Data Types in this article as ADTs, though not to be confused with <em>Algebraic</em> Data Types, covered in <a href="https://ethanbell.me/algebraic-data-types/">another article</a>).</p>
<p>Note: While the concepts in this article apply to all programming languages, the specific examples are drawn from the C programming language.</p>
<p>ADTs can simply be described as “all the things that describe a type”. For instance,</p>
<p><code class="language-plaintext highlighter-rouge">int</code>’s ADT specifies which values are valid for an <code class="language-plaintext highlighter-rouge">int</code> (whole numbers in the range of <code class="language-plaintext highlighter-rouge">INT_MIN</code> to <code class="language-plaintext highlighter-rouge">INT_MAX</code>) and the operations that are defined for an int (for example, incrementing, decrementing, adding with another <code class="language-plaintext highlighter-rouge">int</code>, etc). Important to note is that some things about <code class="language-plaintext highlighter-rouge">int</code>s are <em>not</em> part of <code class="language-plaintext highlighter-rouge">int</code>’s ADT. For instance, the fact that ints are usually represented as bit strings has nothing to do with the <code class="language-plaintext highlighter-rouge">int</code> ADT. Neither has the fact that <code class="language-plaintext highlighter-rouge">int</code>s can be used as pointers (since that is a language bug/feature rather than a property of the type).</p>
<p>In general, the set of values which are valid for an ADT are called the <em>domain</em>, and the “things you can do” with an ADT are called the ADT’s <em>operations</em>, or sometimes, <em>API</em> (Application Programming Interface). The ADT does not include how values are stored, nor the specific steps by which operations do their jobs. This is why they are referred to as <em>abstract</em>: the concerns of how these details work is hidden (or <em>abstracted</em>) from the developer.</p>
<p>In C, there are four <em>primitive</em> (sometimes called <em>atomic</em>) data types: <code class="language-plaintext highlighter-rouge">char</code>, <code class="language-plaintext highlighter-rouge">int</code>, <code class="language-plaintext highlighter-rouge">float</code>, and <code class="language-plaintext highlighter-rouge">double</code>. All other data types are built from these. As an example, a <code class="language-plaintext highlighter-rouge">bool</code> is implemented as an <code class="language-plaintext highlighter-rouge">int</code> (where <code class="language-plaintext highlighter-rouge">1</code> has the value <code class="language-plaintext highlighter-rouge">true</code> and <code class="language-plaintext highlighter-rouge">0</code> has the value <code class="language-plaintext highlighter-rouge">false</code>). However, because <code class="language-plaintext highlighter-rouge">bool</code> has an ADT, a developer needn’t ever know this. In order to use a bool, you only need to know that the domain is {<code class="language-plaintext highlighter-rouge">true</code>, <code class="language-plaintext highlighter-rouge">false</code>} and the API is composed of 5 operations: <code class="language-plaintext highlighter-rouge">!</code> (negate), <code class="language-plaintext highlighter-rouge">&&</code> (logical AND), <code class="language-plaintext highlighter-rouge">||</code> (logical OR), <code class="language-plaintext highlighter-rouge">==</code> (logical equality), and <code class="language-plaintext highlighter-rouge">!=</code> (logical inequality / XOR). Note that <code class="language-plaintext highlighter-rouge">=</code> (assignment) is not included in the list of operations: This is because assignment does not actually operate on <code class="language-plaintext highlighter-rouge">bool</code>s, only on <em>variables</em> of type <code class="language-plaintext highlighter-rouge">bool</code>. Consider <code class="language-plaintext highlighter-rouge">true = false</code>: This statement does not compile because <code class="language-plaintext highlighter-rouge">true</code>, while a valid <code class="language-plaintext highlighter-rouge">bool</code> value, is not an assignable variable. Therefore, <code class="language-plaintext highlighter-rouge">=</code> is not part of <code class="language-plaintext highlighter-rouge">bool</code>’s API.</p>
<p>According to <a href="https://web.archive.org/web/20180922184253/http://web.mit.edu/6.005/www/fa14/classes/08-abstract-data-types/">a very good article by MIT</a>, operations on an ADT can be classified as either Creators, Produces, Observers, or Mutators.</p>
<ul>
<li><em>Creators</em> instantiate the ADT, such as the literals <code class="language-plaintext highlighter-rouge">0</code> (for <code class="language-plaintext highlighter-rouge">int</code>) or <code class="language-plaintext highlighter-rouge">'c'</code> (for <code class="language-plaintext highlighter-rouge">char</code>).</li>
<li><em>Producers</em> generate new ADT instances from existing ones (eg, <code class="language-plaintext highlighter-rouge">int</code>’s <code class="language-plaintext highlighter-rouge">+</code>, which takes two <code class="language-plaintext highlighter-rouge">int</code>s and produces a third).</li>
<li><em>Observers</em> take instances of the ADT and return a different type (eg, <code class="language-plaintext highlighter-rouge">double</code>’s <code class="language-plaintext highlighter-rouge">floor</code> observes a <code class="language-plaintext highlighter-rouge">double</code> but returns an <code class="language-plaintext highlighter-rouge">int</code>).</li>
<li><em>Mutators</em> change ADT instances without altering their identity. Atomic ADTs do not have mutators, but data structures (covered in the next article) do. For example, an array’s dereference-and-assign operation (eg, <code class="language-plaintext highlighter-rouge">arr[3] = 5</code>) changes an element of the array without replacing the array itself, so we say it <em>mutates</em> the array.</li>
</ul>
<p>Some languages have <em>type qualifiers</em> which modify a type’s ADT, such as <code class="language-plaintext highlighter-rouge">unsigned</code>. An <code class="language-plaintext highlighter-rouge">unsigned int</code> has a domain of <code class="language-plaintext highlighter-rouge">0</code> to <code class="language-plaintext highlighter-rouge">UINT_MAX</code>, as opposed to an <code class="language-plaintext highlighter-rouge">int</code>’s domain of <code class="language-plaintext highlighter-rouge">INT_MIN</code> to <code class="language-plaintext highlighter-rouge">INT_MAX</code>. The same API applies, but the implementation of the operations might be different, as might the domain.</p>Ethan Belleb@ethanbell.meAbstract Data Types are a crucial construct in everyday programming. They effectively constitute all types which values might have. For the sake of brevity, I will refer to Abstract Data Types in this article as ADTs, though not to be confused with Algebraic Data Types, covered in another article).Algebraic Data Types2019-02-01T00:00:00+00:002019-02-01T00:00:00+00:00https://ethanbell.me/algebraic-data-types<p>Recently, type theory is quite the hot topic in the languages and theoretical CS research spaces. Seeing this, and not wanting to exclude any major sub-disciplines or research areas from consideration as I review prospective graduate programs, I decided to try to teach myself the intuitive basics of the theory. This necessarily (or at least I hope it was necessary, for if not then I don’t want to think about how much time I’ve wasted) led me down a few rabbit holes, and introduced me to a <em>ton</em> of new vocabulary. Among the definitions, some terms stood out as both somewhat opaque, and particularly critical to a foundational understanding of many topics. Algebraic data types fall into this intersection.</p>
<p>While I first came across algebraic data types (ADTs – not to be confused with <em>abstract</em> data types) in the context of type-theoretic mathematics, I quickly saw the applications to my everyday coding. Interestingly, the relevance to regular programming was clear across a wide breadth of languages. From my personal favorite Scala, to the language I wish I was smart enough to have as my favorite Haskell, to my company’s language of choice at the time C#, to the university-mandated C and C++, all of these languages had type systems that could be modeled using ADTs. While the usefulness of this model was certainly more apparent in the strongly-typed functional languages of Scala and Haskell, thinking about data in terms of ADTs helped me gain clarity in designing data structures independent of language.</p>
<p>So, what are ADTs? Algebraic data types are composite types (ie, types made of other types) that have properties that mimic set-theoretic properties. If that’s just word soup to you, don’t worry, it would have been to me too. I find it easier to get a basic grasp of the concept using examples. Let’s start with a tuple, basically a container for other types in some particular order, kind of like a class with no methods and no property names. One tuple type may be <code class="language-plaintext highlighter-rouge">(Boolean, Int, Byte)</code>. Another may be <code class="language-plaintext highlighter-rouge">(String, Boolean)</code>. Yet another could be <code class="language-plaintext highlighter-rouge">(String, Nothing)</code>. A tuple is a very simple algebraic data type. In particular, it is a <em>product type</em>, the meaning of which we will get to later. Other product types include classes (which, as mentioned, are basically tuples with names) and C/C++ structs.</p>
<p>Let’s consider another ADT, <code class="language-plaintext highlighter-rouge">Either</code>: <code class="language-plaintext highlighter-rouge">Either</code> has a “left type” and a “right type”, and the value of the <code class="language-plaintext highlighter-rouge">Either</code> is <em>either</em> an instance of the left type or one of the right type. Some <code class="language-plaintext highlighter-rouge">Either</code> types may be <code class="language-plaintext highlighter-rouge">Either[Byte, Boolean]</code>, or <code class="language-plaintext highlighter-rouge">Either[Int, String]</code>. An <code class="language-plaintext highlighter-rouge">Either</code> is another algebraic data type. It is a <em>sum type</em>, the meaning of which, again, I hope will be clear very soon. Other sum types include <code class="language-plaintext highlighter-rouge">Option</code> (aka <code class="language-plaintext highlighter-rouge">Maybe</code> in Haskell/Scalaz), <code class="language-plaintext highlighter-rouge">Try</code>, and even C <code class="language-plaintext highlighter-rouge">union</code>-s.</p>
<p>Hopefully by now you have some intuition of what sorts of things may be product types, and what may be sum types. In my mind, when the above was all I had to go on, I basically thought the following: “A product type is like those children’s pegboard games with different shapes and slots to match the shapes. Each hole is a type and the whole board is a product type. You need to fill each hole to complete the product type, and each inner type is available side-by-side. A sum type is like if the pegboard had only one hole, constructed in such a way that it it will fit only certain pegs, but not all. For example, the hole may fit a square or a triangle, but not a circle. Further, to complete the sum type, you can only put 1 shape in the hole at a time. If a triangle is in the hole, a square cannot fit, and visa versa. Similarly, you can never put in a shape the hole wasn’t designed for. A rhombus won’t fit a hole designed to take only squares and circles!”.</p>
<p>If you think me crazy after reading the above, I won’t blame you. Obviously, that approach to thinking about ADTs is brittle and hard to convey, and doesn’t really explain why these things are called “products” and “sums”. For a better explanation (actually two), we turn to our old friend, counting.</p>
<p>Consider our above tuple types. In particular, let’s first look at the types they’re composed of. Boolean, Int, String, Byte, and Nothing. For each, let’s jot down how many values of that type can be instantiated.</p>
<table>
<tr>
<td><strong>Type</strong>
</td>
<td><strong>Count</strong>
</td>
</tr>
<tr>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="nc">Boolean</span></code></pre></figure>
</td>
<td>\(2\) (true and false)
</td>
</tr>
<tr>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="nc">Int</span></code></pre></figure>
</td>
<td>\(2^{31} - 1\) or similar (depending on context)
</td>
</tr>
<tr>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="nc">String</span></code></pre></figure>
</td>
<td>Depends on implementation, but usually \(\text{a lot}\)
</td>
</tr>
<tr>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="nc">Byte</span></code></pre></figure>
</td>
<td>\(256\)
</td>
</tr>
<tr>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="nc">Nothing</span></code></pre></figure>
</td>
<td>\(0\)
</td>
</tr>
</table>
<p>One type which may not be familiar is Nothing. Nothing is the name of the “bottom type” (denoted ⏊) in Scala, meaning it is a subtype of every other type in the language. It has no values and cannot be instantiated, much like void in many other C-like languages.</p>
<p>Now, consider the tuple types themselves in a similar fashion. To determine the total number of possible values for a tuple, we need to consider every possible combination of the values of its constituent types. If we were dealing with a tuple composed of 2 booleans, we’d have 4 options: <code class="language-plaintext highlighter-rouge">(true, true)</code>, <code class="language-plaintext highlighter-rouge">(false, true)</code>, <code class="language-plaintext highlighter-rouge">(true, false)</code>, and <code class="language-plaintext highlighter-rouge">(false, false)</code>. Using the technique for counting problems taught in any discrete mathematics class, we multiply the potential value counts for each member of the tuple to get the count for the tuple overall.</p>
<table>
<tr>
<td><strong>Type</strong>
</td>
<td><strong>Count</strong>
</td>
</tr>
<tr>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="o">(</span><span class="nc">Boolean</span><span class="o">,</span> <span class="nc">Boolean</span><span class="o">)</span></code></pre></figure>
</td>
<td>\((2)*(2) = 4\)
</td>
</tr>
<tr>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="o">(</span><span class="nc">Boolean</span><span class="o">,</span> <span class="nc">Int</span><span class="o">,</span> <span class="nc">Byte</span><span class="o">)</span></code></pre></figure>
</td>
<td>\((2)*(2^{31} - 1)*(256) = (2^{40})-512\)
</td>
</tr>
<tr>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="o">(</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Boolean</span><span class="o">)</span></code></pre></figure>
</td>
<td>\((\text{a lot})*(2) = \text{a lot}\)
</td>
</tr>
<tr>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="o">(</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Nothing</span><span class="o">)</span></code></pre></figure>
</td>
<td>\((\text{a lot})*(0) = 0\)
</td>
</tr>
</table>
<p>As noted, the total number of values possible for these tuple types is precisely the product of the number of possible values of each of their constituent types! Therefore, it makes sense to call tuples a <em>product type</em>! Let’s repeat the same exercise for the sum types we called out earlier. Any guesses how that might go?</p>
<table>
<tr>
<td><strong>Type</strong>
</td>
<td><strong>Count</strong>
</td>
</tr>
<tr>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="nc">Either</span><span class="o">[</span><span class="kt">Byte</span>, <span class="kt">Boolean</span><span class="o">]</span></code></pre></figure>
</td>
<td>\(256 + 2 = 258\)
</td>
</tr>
<tr>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="nc">Either</span><span class="o">[</span><span class="kt">Int</span>, <span class="kt">String</span><span class="o">]</span></code></pre></figure>
</td>
<td>
\((2^{31} - 1) + \text{a lot} = \text{a lot}\)
</td>
</tr>
<tr>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="nc">Option</span><span class="o">[</span><span class="kt">Byte</span><span class="o">]</span></code></pre></figure>
</td>
<td>\(256 + 1 = 257\) (ie, 256 <code>Some[Byte]</code>) + 1 <code>None</code>)
</td>
</tr>
</table>
<p><em>Sum types</em> have a possible number of values equal to the <em>sum</em> of their composite types! Who’d have guessed?</p>
<p>The astute reader may notice that I promised two mathematical explanations for the definition of sum and product types, but have so far only offered one. Well, remember how I mentioned set theoretic properties? What if we define types as <em>sets</em> of possible values? Boolean \( = \{true, false\} \) and so on. Well, then tuples can be defined as the cartesian product of those sets. For example, <code class="language-plaintext highlighter-rouge">(String, Boolean)</code> becomes String \(\times\) Boolean. <code class="language-plaintext highlighter-rouge">(String, Nothing)</code> becomes Nothing, because \( A \times \varnothing = \varnothing\) for any set \(A\). Similarly, sum types can be defined in terms of sums (aka disjoint unions) of sets. So <code class="language-plaintext highlighter-rouge">Either[Byte, Boolean]</code> is Byte \(\cup\) Boolean, while <code class="language-plaintext highlighter-rouge">Option[Byte]</code> is Byte \(\cup\) \(\{\)<code class="language-plaintext highlighter-rouge">None</code>\(\}\). There is a similar, though less intuitive, definition for <em>quotient types</em>, but I’ll leave that out of this article for the sake of brevity.</p>
<p><em>This article is based on an untitled functional programming talk given by <a href="https://github.com/gstro">Greg Stromire</a>, who in turn based the relevant sections on <a href="https://tpolecat.github.io/presentations/algebraic_types.html">“Introduction to Algebraic Data Types in Scala”</a> by Rob Norris</em></p>Ethan Belleb@ethanbell.meRecently, type theory is quite the hot topic in the languages and theoretical CS research spaces. Seeing this, and not wanting to exclude any major sub-disciplines or research areas from consideration as I review prospective graduate programs, I decided to try to teach myself the intuitive basics of the theory. This necessarily (or at least I hope it was necessary, for if not then I don’t want to think about how much time I’ve wasted) led me down a few rabbit holes, and introduced me to a ton of new vocabulary. Among the definitions, some terms stood out as both somewhat opaque, and particularly critical to a foundational understanding of many topics. Algebraic data types fall into this intersection.Programming Paradigms, Compared2018-08-07T00:00:00+00:002018-08-07T00:00:00+00:00https://ethanbell.me/programming-paradigms<p>The frontier of computer science seems to change from day to day. This is more evident in some coding ecosystems than others (Javascript, for example, being notorious for replacing its core tools with incredible frequency). Paradigms are no exception to this. The concept of what defines a “functional language” or a “declarative syntax” change frequently, and many such definitions, often in conflict with one another, may be easily found all over the Internet and other resources. However, the general idea of what a each paradigm means has some universality, it’s just the details necessitated by a formal definition that vary.</p>
<p>In this post, I make no claim to an authoritative definition of the terms and paradigms I discuss. I do hope to convey my personal understanding of each of these terms, in order that it might provide some clarity and context for you to form your understanding.</p>
<p>One final thing to note before we dive in is that few, if any, languages fall strictly within a single paradigm. A language may be primarily procedural but still support some features of a functional language, for instance. The programming paradigms are really more <em>styles</em> of code than language characteristics, but some language features encourage and facilitate certain paradigms.</p>
<p>First up, procedural programming. Procedural programming is any programming style which is based around <em>procedures</em>. A procedural language is a language which works best when used procedurally. These are not to be confused with (and are in many ways the opposite of) functional languages, discussed later. The question then becomes, what is a procedure as opposed to a function? In the context of describing a paradigm, as I do now, a procedure is a set of instructions for how to modify data, and these instructions are usually as independent of the data as possible. Therefore, this modification is usually done in-place. For example, increment might be a procedure taking one symbol and consisting of the instruction “add 1 to the value the symbol refers to”. Then we might call <code class="language-plaintext highlighter-rouge">increment(a)</code> in order to increase a’s value by 1. This is as opposed to a function increment’ which returns the value of <code class="language-plaintext highlighter-rouge">a + 1</code> without changing a itself. The epitome of the procedural paradigm is the C programming language. Much code within the standard libraries are identifiable as procedures by the fact that they return little to no output, and instead do work on the value of a pointer passed in as one of their parameters. Procedural code often has the advantage of being very memory-efficient, since it tends to modify data in-place. However, purely procedural code can also be incredibly difficult to maintain and reason about, since data is managed independently of the instructions that modify that data, giving them plenty of opportunity to get out of sync and cause unexpected bugs.</p>
<p>As mentioned, the opposite (in some sense) of procedural programming is functional programming. The functional style does work in units of <em>functions</em>. Functions are just like mathematical functions: they take some input and give some output. They don’t have any side effects. They don’t modify data in place, read from the keyboard, write to the network, or wait on a clock. Functions (and as a result, functional programming) are therefore extremely predictable and easy to reason about / follow. However, because real-world programs necessarily do <em>something</em> (write text to a console or read from a file or whatever else) functional languages must have some way of encapsulating these impure “side effects”. Managing these side effects is done differently in every language, but is the greatest source of confusion and intimidation on the part of functional languages. A great example of an extremely pure functional language is Haskell, whose side effects are captured within a construct called a monad (the <code class="language-plaintext highlighter-rouge">IO</code> monad), explained in another article. However, as evidenced by the fact that explaining the IO system requires an entire other post, these languages can be less intuitive to start working in than others. In spite of this, once you adjust to the common patterns, functional code is both quick to write and quick to read, due to the restriction that functions can’t do anything other than return a value (meaning you don’t have to go chasing for what variables get modified by what, when).</p>
<p>Many language features naturally follow from the basic rule of functional programming - functional languages usually support functions as first-class values, allowing them to be returned from other functions or passed as arguments. They often entirely exclude mutable data structures, and use strong and/or static type systems. These are not, in my opinion, <em>necessary</em> to use the functional paradigm (though I would concur that functions as first-class values are a necessity to be considered a functional language). However, these features do make programming within the functional paradigm much easier.</p>
<p>Object-oriented programming is the style of programming in which data is closely associated with the methods that effect it. This doesn’t necessarily mean the methods must be functions, nor does it mean they must be procedures. It just means that there’s an additional label on every method that says “this method is designed to work on [something]” where [something] is a class of objects. In this way, object-oriented programming is a somewhat orthagonal paradigm to procedural and functional. That is, you can have a procedural and object-oriented program (as you may expect from C++ or Java), or a functional and object-oriented program (as may be expected from Scala or O’Caml), but probably not a functional procedural program.</p>
<p>As with functional programming, there are some common language features you can expect when using object-oriented programming. Classes are typically the unit of encapsulation for (data plus associated methods). Interfaces provide groupings of methods without defining the structure of the data or the implementations of the methods. Inheritance allows one class to implement another, or an interface, indicating that that class will have at least the methods defined on its parent, possibly (if it’s a class implementing a parent class) providing a default implementation. Polymorphism allows a child to be passed in to something that expects its parent, due to the guaranteed similarities. Again, these features are not strictly necessary (in my opinion) to program in an object-oriented style, but you certainly don’t have much of an object-oriented language without them.</p>
<p>Imperative syntax is the style of syntax or programming where you as a programmer are telling the computer what changes to make. Procedural languages tend to have very imperative syntax, with calls like <code class="language-plaintext highlighter-rouge">getcount(counter)</code> and our earlier <code class="language-plaintext highlighter-rouge">increment(a)</code>. These instructions specify <em>what steps</em> should be taken.</p>
<p>In contrast, declarative syntax is the style of syntax or programming where you as a programmer are telling the computer what should be done. That is, your instructions specify <em>what the result</em> should be. The extreme manifestation of declarative syntax are languages like XML or HTML, languages which are little more than formats for data. HTML has no knowledge of, nor does it care, how your browser renders a <code class="language-plaintext highlighter-rouge"><table></code>. It just asserts that a <code class="language-plaintext highlighter-rouge"><table></code> is there. A good example of a benefit of declarative syntax in what would be more commonly considered “programming” is referential transparency. That is, the property of many functional languages asserting that <code class="language-plaintext highlighter-rouge">(doThing(x) + doThing(x))</code> will have exactly the same result as <code class="language-plaintext highlighter-rouge">y = doThing(x); return (y + y)</code>. This may seem intuitive, but consider, as an example, the case where <code class="language-plaintext highlighter-rouge">doThing(x)</code> is a random number generator. Declarative syntax can make it clearer what will happen as a result of your programs, but imperative syntax provides much finer control over how your program runs.</p>
<p>All-in-all, programming is, always has been, and always will be a mess of confusing, overlapping, and even contradicting terminology, but I hope you now have at least a slightly better idea of what each of these more common terms means. There are some other paradigms I didn’t discuss: logic programming, structured programming, etc, but these are mostly obsolete or no longer referred to in industry to the extent that I have never actually heard the phrases said aloud, and therefore excluded them from this discussion.</p>Ethan Belleb@ethanbell.meThe frontier of computer science seems to change from day to day. This is more evident in some coding ecosystems than others (Javascript, for example, being notorious for replacing its core tools with incredible frequency). Paradigms are no exception to this. The concept of what defines a “functional language” or a “declarative syntax” change frequently, and many such definitions, often in conflict with one another, may be easily found all over the Internet and other resources. However, the general idea of what a each paradigm means has some universality, it’s just the details necessitated by a formal definition that vary.The M Word2018-06-27T00:00:00+00:002018-06-27T00:00:00+00:00https://ethanbell.me/the-m-word<p><em>This article continues my eclectic collection of recently-learned-topic reviews. Essentially, when I’m in class or work and come across a topic I find particularly difficult, counterintuitive, or just interesting, I’ll write one of these to hopefully ease the learning process for the next poor sucker who needs to learn the topic. Today, I’ll be discussing monads in a functional programming context.</em></p>
<p><strong>Monads</strong>. For many developers just starting out with functional programming, this word inspires despair. For good cause: the concept of a monad can be incredibly confusing (it certainly was for me!) We see genius PhD types discussing the power of monads and praising them left and right, sometimes describing them using terms like “morphism”, “kleisli composition”, and “applicative”. The density of language used in discussing monads is in one part due to their origins in complex mathematics called category theory and in another part due to many of the people using them having very remarkable IQs and less remarkable social skills. As a response to this, the common approach to explaining monads is to “sneak up” on the concept, either saying “forget about the word Monad, think of a List” or building up a monad from its properties in a very particular context. While this is effective in getting the point across, the indirection makes it hard to explain later in an abstract context, like trying to define a word used in common slang. As <a href="https://www.youtube.com/watch?v=dkZFtimgAcM">Douglas Crockford said,</a> “Once you … understand, ‘Oh, that’s what [a monad] is’, you lose the ability to explain it to anybody else”.</p>
<p>One quick note, I apologize for the weird Scala/C++ hybrid pseudocode dialect I seemed to invent in the course of writing this article</p>
<p>In attempt to break Crockford’s Monadic Curse, we’re going to approach monads directly. So, what is a monad? A monad is, as you’ll usually see it, a type with 2 functions: <code class="language-plaintext highlighter-rouge">unit</code> (aka <code class="language-plaintext highlighter-rouge">return</code> or <code class="language-plaintext highlighter-rouge">point</code>) and <code class="language-plaintext highlighter-rouge">flatMap</code> (aka <code class="language-plaintext highlighter-rouge">bind</code> aka <code class="language-plaintext highlighter-rouge">>>=</code> because haskell likes symbols).</p>
<p><code class="language-plaintext highlighter-rouge">unit</code> takes (something, doesn’t matter what) and returns a (monad) of (something). For instance, List (as a monad) has a <code class="language-plaintext highlighter-rouge">unit</code> which takes a value and returns a List of that value’s type containing only that value. An implementation might look like the following:</p>
<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">List</span><span class="o">::</span><span class="nf">unit</span><span class="o">(</span><span class="n">x</span><span class="k">:</span> <span class="kt">T</span><span class="o">)</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">T</span><span class="o">]</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">List</span><span class="o">(</span><span class="n">x</span><span class="o">)</span>
</code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">flatMap</code> takes a (something in a monad) and returns a (monad) of (something else in the same monad). For example, List (as a monad) has a flatMap which takes a List of values and a function turning that value type into another List. The flatMap then applies the function to each of the values in the list, returning the resultant lists concatenated together. In pseudocode, an implementation might look like:</p>
<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">List</span><span class="o">[</span><span class="kt">T</span><span class="o">].</span><span class="py">flatMap</span><span class="o">(</span><span class="n">funct</span><span class="k">:</span> <span class="kt">T</span> <span class="o">=></span> <span class="nc">List</span><span class="o">[</span><span class="kt">R</span><span class="o">])</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">R</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
<span class="k">var</span> <span class="n">list</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">List</span><span class="o">[</span><span class="kt">R</span><span class="o">]()</span>
<span class="nf">for</span> <span class="o">(</span><span class="n">value</span> <span class="n">in</span> <span class="k">this</span><span class="o">)</span> <span class="o">{</span>
<span class="k">var</span> <span class="n">result</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">R</span><span class="o">]</span> <span class="k">=</span> <span class="nf">funct</span><span class="o">(</span><span class="n">value</span><span class="o">)</span>
<span class="nf">for</span> <span class="o">(</span><span class="n">resultItem</span> <span class="n">in</span> <span class="n">result</span><span class="o">)</span> <span class="nv">list</span><span class="o">.</span><span class="py">append</span><span class="o">(</span><span class="n">resultItem</span><span class="o">)</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">list</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Or, if you’re comfortable with map and flatten:</p>
<div class="language-scala highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">List</span><span class="o">[</span><span class="kt">T</span><span class="o">].</span><span class="py">flatMap</span><span class="o">(</span><span class="n">funct</span><span class="k">:</span> <span class="kt">T</span> <span class="o">=></span> <span class="nc">List</span><span class="o">[</span><span class="kt">R</span><span class="o">])</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">R</span><span class="o">]</span> <span class="k">=</span>
<span class="k">this</span><span class="o">.</span><span class="py">map</span><span class="o">(</span><span class="n">funct</span><span class="o">).</span><span class="py">flatten</span>
</code></pre></div></div>
<p>Furthermore, <code class="language-plaintext highlighter-rouge">flatMap</code> and <code class="language-plaintext highlighter-rouge">unit</code> have to be defined so that the following 3 laws hold:</p>
<table>
<tr>
<th>Name</th>
<th>Law</th>
</tr>
<tr>
<td>Left identity</td>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="nf">unit</span><span class="o">(</span><span class="n">x</span><span class="o">).</span><span class="py">flatMap</span><span class="o">(</span><span class="n">funct</span><span class="o">)</span> <span class="o">==</span> <span class="nf">funct</span><span class="o">(</span><span class="n">x</span><span class="o">)</span></code></pre></figure>
</td>
</tr>
<tr>
<td>Right identity</td>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="nv">m</span><span class="o">.</span><span class="py">flatMap</span><span class="o">(</span><span class="n">unit</span><span class="o">)</span> <span class="o">==</span> <span class="n">m</span></code></pre></figure>
</td>
</tr>
<tr>
<td>Associativity</td>
<td>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="nv">m</span><span class="o">.</span><span class="py">flatMap</span><span class="o">(</span><span class="n">f</span><span class="o">).</span><span class="py">flatMap</span><span class="o">(</span><span class="n">g</span><span class="o">)</span> <span class="o">==</span> <span class="nv">m</span><span class="o">.</span><span class="py">flatMap</span><span class="o">(</span><span class="n">value</span> <span class="k">=></span> <span class="nf">f</span><span class="o">(</span><span class="n">value</span><span class="o">).</span><span class="py">flatMap</span><span class="o">(</span><span class="n">g</span><span class="o">))</span></code></pre></figure>
</td>
</tr>
</table>
<p><em>(This table largely influenced by Trevor Hartman’s <a href="https://devth.com/2015/monad-laws-in-scala">“Monad Laws in Scala”</a>)</em></p>
<p>When you’re just <em>using</em> monads, (and you will almost exclusively be using them: it’s very rare to need to write your own), you don’t need to worry about the laws too much. So, for the developer looking to use monads day-to-day, all you need to know is <code class="language-plaintext highlighter-rouge">flatMap</code> and <code class="language-plaintext highlighter-rouge">unit</code></p>
<p>So, a review. <code class="language-plaintext highlighter-rouge">unit</code> looks like <code class="language-plaintext highlighter-rouge">T => M[T]</code>, and is used to wrap a value into a monad. <code class="language-plaintext highlighter-rouge">flatMap</code> looks like (<code class="language-plaintext highlighter-rouge">M[T]</code>).<code class="language-plaintext highlighter-rouge">(T => M[U]) => M[U]</code>, and is applied to each value in a monad, with the results being combined to form a new monad. These two functions (plus 3 laws) allow for some crazy patterns and features, but they can be seen and used in contexts as simple as Lists.</p>Ethan Belleb@ethanbell.meThis article continues my eclectic collection of recently-learned-topic reviews. Essentially, when I’m in class or work and come across a topic I find particularly difficult, counterintuitive, or just interesting, I’ll write one of these to hopefully ease the learning process for the next poor sucker who needs to learn the topic. Today, I’ll be discussing monads in a functional programming context.Press F to Pay Respects: Your FTP Client is Dead2018-04-23T00:00:00+00:002018-04-23T00:00:00+00:00https://ethanbell.me/ftp-vulnerabilities<p><em>This article was written in collaboration with students at Pacific University during the CS435 (Computer Security) course. Thanks to <a href="http://zeus.cs.pacificu.edu/shereen">Shereen Khoja</a> for supervising</em></p>
<h2 id="a-brief-history-of-ftp">A Brief History of FTP</h2>
<p>The uncreatively named FTP – File Transfer Protocol – is a protocol for file transfer dating back to 16 April 1971 (as <a href="https://tools.ietf.org/html/rfc114">RFC 114</a>). Since then, it’s had some updates, <a href="https://tools.ietf.org/html/rfc765">RFC 765</a> and <a href="https://tools.ietf.org/html/rfc959">959</a> moving the protocol on to TCP/IP, <a href="https://tools.ietf.org/html/rfc1579">RFC 1579</a> and <a href="https://tools.ietf.org/html/rfc2428">2428</a> adding some functionality, and <a href="https://tools.ietf.org/html/rfc2228">RFC 2228</a> adding security extensions. Despite these updates, the core of FTP is much the same as it was in 1971, and many FTP clients written even today adhere closely to the minimum functionality required by the standard, in order to guarantee compatibility.</p>
<p>In general, an FTP connection flow looks something like this:
<img src="https://i.imgur.com/pg5KwSw.png" alt="Image credit http://www.tcpipguide.com/free/t_FTPControlConnectionEstablishmentUserAuthenticatio-2.htm" /></p>
<h2 id="the-vulnerability">The Vulnerability</h2>
<p>The security-astute minds out there may have already seen a problem in this protocol: <strong>Nowhere in this standard flow is a maximum message size specified.</strong> This introduces the possibility of a buffer overflow, since the naïve solution for many developers will go as follows:</p>
<ul>
<li>Have a local character array with some estimated maximum command length, say, 400 characters</li>
<li>Upon receiving a message, copy it to the above array</li>
<li>Handle the command</li>
</ul>
<p>This would be fine, if there were some guarantee the message wouldn’t exceed the estimated length. Unfortunately, since FTP doesn’t specify a limit on the message size, it can be of any length. If the FTP application doesn’t have a system to detect this and allocate the additional memory required, the message will likely by copied right over important data in the stack, like the return address pointer. This could be exploited to make the return address lead to some malicious code. In recent exploits (eg CVE-2018-7573), the tendency is to send a message consisting of a buffer full of “F” followed by a malicious return address, or else just an extremely large number of “F” characters to cause a segmentation fault in the application.</p>
<p><img src="https://i.imgur.com/2tiQT9l.png" alt="Image credit Jonathan Ganz jonganz.com" /></p>
<p>(This graphic shows filling the buffer with “A” rather than “F”, but the concept is the same)</p>
<h2 id="the-attacks">The Attacks</h2>
<p>In our research, we came across many instances of buffer overflows in FTP clients and servers, from the esoteric “FTPShell” client to the default client built in to Windows to the default server shipped with Microsoft’s IIS server suite. The effects ranged from crashing the application (bad) to arbitrary code execution (really bad). Just to name a few:</p>
<ul>
<li><a href="https://www.cvedetails.com/cve/CVE-2018-7573/">CVE-2018-7573</a></li>
<li><a href="https://www.cvedetails.com/cve/CVE-2017-6465/">CVE-2017-6465</a></li>
<li><a href="https://www.cvedetails.com/cve/CVE-2014-1215/">CVE-2014-1215</a></li>
<li><a href="https://www.cvedetails.com/cve/CVE-2010-3972/">CVE-2010-3972</a></li>
<li><a href="https://www.cvedetails.com/cve/CVE-2009-3364/">CVE-2009-3364</a></li>
<li><a href="https://www.cvedetails.com/cve/CVE-2009-1611/">CVE-2009-1611</a></li>
<li><a href="https://www.cvedetails.com/cve/CVE-2002-0608/">CVE-2002-0608</a></li>
<li><a href="https://www.kb.cert.org/vuls/id/276653">VU#276653</a></li>
</ul>
<p>The prevalence of these vulnerabilities, the breadth of applications and vendors affected, and the frequency at which they recur all indicate that FTP client and server developers need to start taking steps to protect their applications. Of course, we can’t expect every developer to independently spend their time coming up with a solution to protect their FTP applications from buffer overflows, and luckily a standardized (but optional) extension to FTP does exist to prevent these issues.</p>
<h2 id="countermeasures">Countermeasures</h2>
<p>As mentioned, RFC 2228 does provide some extensions to help protect against this attack, namely the PBSZ (“protection buffer size”) command. This works by allowing the client and server to negotiate a maximum packet/message size, providing a buffer length the client and server can use to prevent buffer overflow, but requires both the server and the client to implement its standard, which goes above and beyond what is required to make FTP work for its basic job of transferring files between well-meaning parties. Still, as demonstrated by the many vulnerability reports above, this attack vector will be discovered in an application sooner rather than later, and is well worth protecting against.</p>Ethan Belleb@ethanbell.meThis article was written in collaboration with students at Pacific University during the CS435 (Computer Security) course. Thanks to Shereen Khoja for supervisingFair Division2018-04-21T00:00:00+00:002018-04-21T00:00:00+00:00https://ethanbell.me/fair-division<p><em>This article continues my eclectic collection of recently-learned-topic reviews. Essentially, when I’m in class or work and come across a topic I find particularly difficult, counterintuitive, or just interesting, I’ll write one of these to hopefully ease the learning process for the next poor sucker who needs to learn the topic. Today, I’ll be discussing the Fair Division problem, with a particular emphasis on the subset of problems which involve continuous value functions, and on systems with only a proportional division criterion.</em></p>
<p>Just about everyone who made it through childhood had heard the fairness algorithm “I cut, you choose”, and it is a good one. Say that Alice and Bob want to split a cake. In order to ensure both get what they consider half (or more) of the cake, Alice cuts the cake into two pieces she feels are exactly equal in quality, and Bob chooses the one he prefers. In this way, Alice is guaranteed a piece of cake whose value she perceives is exactly ½ of the total value of the pieces, since she cuts the cake herself. Bob, then, gets his pick of the halves, so he’ll only pick the piece worth most to him, guaranteeing he gets at least half of his perceived value of the slices. Something amazing to note about this solution is that it doesn’t matter how you judge the value of the cake. Maybe Alice is looking for the most frosting but Bob is looking for the biggest filling layer. Either way, each can choose according to their own criteria, and so will end up with a piece they value.</p>
<p>Unfortunately, when you have 3 or more people (let’s say N people), the problem of fair cake division is more difficult. In this context, we’ll take “fair division” to mean a division where each of the N individuals receives a portion of the cake they consider to have at least 1/nth the total value of the slices. So, for 3 people, each person will perceive their slice as being worth at least 1/3rd the value of all the slices combined.</p>
<p>One naive approach goes like this: Alice, Bob, and Charlie, as before, wish to split a cake. Alice and Bob play “I cut, you choose” on the cake as a whole, then each divides their half into three pieces of equal value to them. Charlie then chooses his favorite third from each. As before, all parties are satisfied they’ve received at least their fair 1/nth of the cake. Supposing Dean now joins, and wants a quarter of the total cake, the process can be repeated, with Alice, Bob, and Charlie each dividing their pieces into fourths they see as fair, then Dwayne choosing his favorite fourth from each set. It’s not hard to see how this extends to 5, 6, 7, or more people.</p>
<p>The naive approach does, of course, have a big problem. The cake gets cut A LOT. Pretty soon, you’re splitting crumbs, and you’ve ruined a piece of perfect chocolate goodness. In particular, we can associate N to cuts as follows:</p>
<table>
<thead>
<tr>
<th><strong>N</strong></th>
<th><strong>Cuts</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>2</td>
<td>1</td>
</tr>
<tr>
<td>3</td>
<td>1+2*2=5</td>
</tr>
<tr>
<td>4</td>
<td>1+1*2*2+2*3*3=23</td>
</tr>
<tr>
<td>n</td>
<td>n!-1</td>
</tr>
</tbody>
</table>
<p>So, our current cake-cutting algorithm is O(N!). That is a lot of cuts indeed! Let’s clean it up. I’m a particular fan of a linear solution (ie, a solution requiring N-1=O(N) cuts) that goes something like this: A mediator holds a knife over the cake, slowly moving it without changing its angle, from the left of the cake to the right. At any point, any individual may declare they wish the cake to be cut where the knife rests, taking the entire section of the cake to the left of the blade. In this way, each individual is guaranteed a piece they are satisfied with, since all but the last person declare when they feel the piece is fair. As for the last person, they get the remaining cake, and since they had not yet requested a cut, they are necessarily getting more than what they perceive as a fair minimum. This solution requires the minimum number of cuts, and has the benefit of each person’s portion consisting of a single connected slice of cake rather than whatever mishmash of trimmings provided by other methods. This method isn’t free, however. It requires all parties involved to be continuously monitoring the status of the knife and the cake, and to, at each possible moment, make a decision about whether they deem the current potential cut fair or not. This is a lot of thinking. So, we search for a discrete solution.</p>
<p>Our final algorithm, one requiring only n-1 cuts, as before, but this time discrete, goes as follows: Each person is given a knife to place, all parallel to one another, wherever they consider the midway point of the cake (or floor(n/2)/n for odd numbers, eg ⅖). The mediator cuts the cake between the middle knives, ensuring that for each resultant subcake, the opinion of everyone whose knife was over that subcake is that the subcake is worth more than ½ (or the fraction as before) of the total cake. This is done recursively until there are only one to two knives over each section of cake, at which point the remaining conflicting knife-holders play “I cut, you choose”, and any solitary knife-holders get their complete section. In this manner, we have established a fair cake-cutting algorithm requiring only a finite number of decisions, as opposed to the continuous algorithm before which required infinite instantaneous decisions.</p>
<p>I you find this topic interesting, you might want to know that in this article, we’ve been concerned with “proportional division” (the PR criterion). That is, we’re only concerned with making sure everyone gets at least their 1/n of the cake. If you want to pursue this topic further on your own, two areas of further research jump out. The first is the formalization or addition of additional criteria to the fair division problem. Envy-free (the EF criterion) is the obvious place to start. Rather than saying “Each person must get at least a subjectively fair portion”, EF guarantees “Every person will see their portion as at least as good as everyone else’s portions”. That’s a bit outside the scope of this article, but it’s certainly interesting. The other area of potential interest for those looking to deep-dive into the topic is applications of fair division to “bad cakes”. For example, splitting labor or rent, known as “envy-free chore division” or “fair division of bads”.</p>
<p><em>This article was primarily based on the talk “Halving your Cake” by Deanna Haunsperger from the Pacific Northwest MAA Chapter Meeting 2018, with some auxiliary research from miscellaneous websites and textbooks.</em></p>Ethan Belleb@ethanbell.meThis article continues my eclectic collection of recently-learned-topic reviews. Essentially, when I’m in class or work and come across a topic I find particularly difficult, counterintuitive, or just interesting, I’ll write one of these to hopefully ease the learning process for the next poor sucker who needs to learn the topic. Today, I’ll be discussing the Fair Division problem, with a particular emphasis on the subset of problems which involve continuous value functions, and on systems with only a proportional division criterion.The Lions-Eating Problem2017-10-05T00:00:00+00:002017-10-05T00:00:00+00:00https://ethanbell.me/lions-eating-problem<p><em>This article continues my eclectic collection of recently-learned-topic reviews. Essentially, when I’m in class or work and come across a topic I find particularly difficult, counterintuitive, or just interesting, I’ll write one of these to hopefully ease the learning process for the next poor sucker who needs to learn the topic. Today, I’ll be discussing the Lions-Eating Problem, otherwise known as the lions and lambs game.</em></p>
<p>In this “game” (ie, scenario), there is a single defenseless lamb, and some hyper-rational but hungry lions. These lions always act in their best interest, with the following goals and priorities:</p>
<ol>
<li>Stay alive</li>
<li>Eat</li>
</ol>
<p>That is, their compulsion to stay alive will beat out their compulsion to eat. The catch is, once a lion eats, it falls asleep and becomes vulnerable to being eaten by any other lion. The question posed then is as follows: For what number[s] of lions will the lamb be eaten?</p>
<p>The first (flawed) solution that might come to mind (as did for me) is that the lamb will never be eaten when there are multiple lions. After all, if a lion eats the lamb, it then becomes prey for all other lions. However, this is not correct. Below I’ll outline the correct solution, and hopefully the reason the previous solution is flawed will become apparent.
Let’s build a solution somewhat inductively. Suppose there is only 1 lion. Naturally, the lion will eat the lamb, since it is hungry and there are no other lions to worry about.</p>
<p>Now, let’s look at the case of 2 lions. Suppose one lion chooses to eat the lamb. Then the now-fed lion falls asleep and the remaining lion eats it. Note that the situation after the first lion has eaten is equivalent to the situation with only 1 lion: one defenseless creature, and one active lion. Since these lions are hyper-rational and their primary goal is survival, neither lion would allow themselves to be eaten in this manner. Therefore, with 2 lions, the lamb survives.</p>
<p>Moving on, let’s evaluate 3 lions. If one lion (the fastest or closes to the lamb) eats the lamb and falls asleep, we’re left with a situation equivalent to that of 2 lions: neither of the awake lions wish to eat the sleeping one, for they will then be eaten themselves. Thus, the lion who eats first may sleep soundly knowing she is safe. Since there is no threat to her life, she realizes she is free to satisfy her lesser need of wishing to eat.</p>
<p>You may now see a pattern forming. Let’s go one further, and then review if this pattern holds. With 4 lions, if one eats, it becomes the lamb in the 3-lion situation, and will thus be eaten. Since the lions wish to live above all else, no lion will eat and thus become prey for one of the remaining 3, and so the lamb may graze in peace.</p>
<p>As we can see, any odd number of lions will eat, and any even number will not. This is because with an even number of lions, an odd number of lions will be left to eat the first lion. With an odd number, a lion may eat leaving an even number in a stalemate. This seems circular, until you remember the base case of a single lion, who may obviously eat without being eaten.</p>
<p><em>This article was primarily based on the week 2 seminars for the ECN214 - Games and Strategies class offered by Queen Mary University of London’s School of Economics and Finance in the Fall of 2017.</em></p>Ethan Belleb@ethanbell.meThis article continues my eclectic collection of recently-learned-topic reviews. Essentially, when I’m in class or work and come across a topic I find particularly difficult, counterintuitive, or just interesting, I’ll write one of these to hopefully ease the learning process for the next poor sucker who needs to learn the topic. Today, I’ll be discussing the Lions-Eating Problem, otherwise known as the lions and lambs game.Why a Blog?1998-01-01T00:00:00+00:001998-01-01T00:00:00+00:00https://ethanbell.me/why-a-blog<p>This website has an odd format. Profile off to the side, a few lines of text, but mostly just empty space. Why? Who creates a blog with no content? Well, I do. I’ve turned my main webpage into this blog format in the hopes of pushing myself towards one of my goals as a developer: stewardship. Early on in my career, I was a part of a brand new company still forming its identity, both its brand and its culture. We talked a lot about culture, about image, and most of all, about values. My boss convinced me that stewardship is a pinnacle virtue in the tech industry. That is, taking what you’ve learned and not only gaining from it yourself, but helping others to learn and gain from that knowledge.</p>
<p>Since that conversation, I’ve wanted to have a development blog. A place where, after finally managing to comprehend a tricky topic, I can try to rephrase the explanation in the way that made it “click” for me. Currently, as a student, with a job, etc, I don’t have the spare time to manage such a blog. Yet, I will make my website this blog, as a reminder to one day fulfill that goal, and represent the value of stewardship in industry.</p>Ethan Belleb@ethanbell.meThis website has an odd format. Profile off to the side, a few lines of text, but mostly just empty space. Why? Who creates a blog with no content? Well, I do. I’ve turned my main webpage into this blog format in the hopes of pushing myself towards one of my goals as a developer: stewardship. Early on in my career, I was a part of a brand new company still forming its identity, both its brand and its culture. We talked a lot about culture, about image, and most of all, about values. My boss convinced me that stewardship is a pinnacle virtue in the tech industry. That is, taking what you’ve learned and not only gaining from it yourself, but helping others to learn and gain from that knowledge.