The Renegade Coder https://therenegadecoder.com Code First. Ask Questions Later. Sat, 13 Jul 2019 01:53:52 +0000 en-US hourly 1 https://wordpress.org/?v=5.2.2 https://i0.wp.com/therenegadecoder.com/wp-content/uploads/2017/05/the-renegade-coder-icon-cropped.png?fit=32%2C32&ssl=1 The Renegade Coder https://therenegadecoder.com 32 32 127809749 Solutions to the Readers-Writers Problem https://therenegadecoder.com/code/solutions-to-the-readers-writers-problem/ https://therenegadecoder.com/code/solutions-to-the-readers-writers-problem/#respond Fri, 19 Jul 2019 14:00:29 +0000 https://therenegadecoder.com/?p=17172

In this third installment of the qualifying exam sequence, we look to tackling a specific process synchronization problem: Readers-Writers.

The post Solutions to the Readers-Writers Problem appeared first on The Renegade Coder.

]]>

If you’ve been following along, I’m currently studying for my PhD qualifying exam. As a part of that exam, I need to brush up on my operating systems knowledge a bit. Previously, I covered a few process synchronization mechanisms, and now I want to start digging into how those mechanisms can be used to solve real problems like the Readers-Writers problem.

Table of Contents

Readers-Writers Problem Overview

In concurrency, one of the common challenges is balancing who has access to a shared variable. In particular, what sort of rules should we set around shared memory access, so that actions are safe but also efficient?

More specifically, the Readers-Writers problem focuses on the challenges related to balancing threads or processes which either wish to read from a shared memory location or write to it. In other words, how do we go about scheduling the threads such that we get our desired outcome (i.e. readers priority, writers priority, etc.)?

In this article, we’ll look at a few Readers-Writers scenarios and try to solve them using some of the mechanisms we chatted about last time like semaphores and monitors. To be clear, all code in this article will be pseudocode except potential examples leveraging Java’s concurrency features. All examples are borrowed from The Ohio State University’s CSE 6431 lecture notes:

Naturally, all analysis is my own.

Readers-Writers Problem Solutions

In this section, we’ll look at various solutions to the Readers-Writers problem using different process synchronization mechanisms. Each subsection contains a different type of solution which are subsequently organized into subsections by mechanism. Also, I should mention that solutions are borrowed from various Ohio State University CSE 6431 course lecture slides, but analysis is my own.

Serial Solution

Orchestrating several readers and writers can be challenging. One way to solve that issue is to organize the reads and writes such that only one process can access shared memory at a time. With this solution, correctness is easy to achieve. However, efficiency is not guaranteed as there is no mechanism for process priority.

Semaphores

With semaphores, we can define two procedures: reader and writer. Each procedure is protected by the same mutex:

procedure reader():
    P(mutex)
    <read>
    V(mutex)

procedure writer():
    P(mutex)
    <write>
    V(mutex)

Monitors

With monitors, the shared resource can be defined inside the monitor. Then, we setup two procedures: reader and writer. Since monitor resources are protected, we can casually call the procedures without worrying about any race conditions:

procedure reader():
    <read>

procedure writer():
    <write>

In general, this will get the job done, but it’s not ideal.

Concurrent Reader Solution

Since read operations have no affect on a shared resource, we usually allow them to occur concurrently. In other words, if two readers happen to come along when there is nothing writing to our shared resource, we should let both readers read.

Semaphores

With semaphores, the reading process has to be broken into three stages:

  1. Check if it is safe to read (i.e. no writers currently writing)
  2. Read
  3. Check if it is safe to write (i.e. no more readers)

Also, we have to introduce an additional mutex, so we can start tracking readers in one queue and writers in another queue. On top of all that, we also have to introduce a shared variable which we’ll use to track the number of active readers:

procedure reader():
    # Stage 1
    P(reader_mutex)
    if readers = 0:
        P(writer_mutex)
    readers++
    V(reader_mutex)

    # Stage 2
    <read>

    # Stage 3
    P(reader_mutex)
    readers--
    if readers = 0:
        V(writer_mutex)
    V(reader_mutex)

procedure writer():
    P(writer_mutex)
    <write>
    V(writer_mutex)

Notice how the readers variable is used to draw a connection between the readers and writers. If a reader realizes it’s first, it needs to snag the writer mutex to avoid any shared memory access issues. If successful, the readers hold onto that mutex until there aren’t any readers left.

If for some reason the first reader doesn’t get the writer mutex, it’s stuck waiting while also holding onto the reader mutex. In other words, all readers are frozen until the first reader gets the writer mutex.

Monitors

Like semaphores, the monitors solution to concurrent reader access needs a few changes. In particular, we’re going to need to split the reader procedure into two procedures. That way, we can remove the reading functionality from the monitor, so reads don’t occur serially. In addition, we’ll need to define a shared readers variable just like before.

That said, there is a slight difference in the monitor solution. Instead of maintaining two queues explicitly, we maintain one using a condition variable called writer:

procedure begin_read():
    readers++

# Reading occurs between these procedures

procedure end_read():
    readers--
    if readers = 0:
        writer.signal

procedure write():
    if readers > 0:
        writer.wait
    <write>
    writer.signal

Since only one process can execute a monitor procedure at a time, we don’t have to worry about any sort of race conditions in that regard. However, since the shared resource (i.e a file) is not protected by our monitor, we have to prevent writers from writing during concurrent reads. To do that, we introduce a writer condition variable which we use to stall writers if there are any readers.

Otherwise, life is pretty simple for a reader. If we’re able to read (i.e. not blocked by the monitor), we increment the number of readers before reading. After reading, we decrement the number of readers. If the current reader is the last reader, it hands control off to any waiting writers.

Readers’ Priority Solution

In essence, the concurrent reader solution works by giving priority to whichever process arrives first. To some extent, the readers get priority. After all, as long as there are readers, they will continue to read. However, writers never hand off control to readers, so it’s possible that writers could starve readers for awhile (and vice versa).

If we want a true readers’ priority solution, we have to look into a mechanism where writers pass control over to readers when they’re finished.

Semaphores

In order to craft a readers’ priority solution with semaphores, we have to introduce yet another semaphore:

procedure reader():
    # Stage 1
    P(reader_mutex)
    if readers = 0:
        P(writer_mutex)
    readers++
    V(reader_mutex)

    # Stage 2
    <read>

    # Stage 3
    P(reader_mutex)
    readers--
    if readers = 0:
        V(writer_mutex)
    V(reader_mutex)

procedure writer():
    P(sync_mutex)
    P(writer_mutex)
    <write>
    V(writer_mutex)
    V(sync_mutex)

At first glance, this solution looks exactly like the concurrent readers solution. Of course, the difference is in the writer procedure which leverages the new mutex. How could two additional lines guarantee readers’ priority?

As it turns out, the new mutex now ensures that writer processes are only ever enqueued for the writer_mutex when they already have the sync_mutex. In other words, there can only ever be one writer waiting for the writer_mutex at a time. As a result, there is no way for a writer to pass control off to another writer if a reader is waiting for the writer_mutex.

Monitors

Unfortunately, the monitor solution isn’t nearly as elegant as the semaphore solution. On top of adding a new condition variable and a new shared variable, the monitor solution needs to break apart its writer procedure:

procedure begin_read():
    if writing:
        safe_read.wait
    readers++
    safe_read.signal

procedure end_read():
    readers--
    if readers = 0:
        safe_write.signal

procedure begin_write():
    if writing or readers > 0:
        safe_write.wait
    writing = true

procedure end_write():
    writing = false
    if safe_read.queue:
        safe_read.signal
    else"
        safe_write.signal

Unlike the previous monitor solution, this solution relies quite a bit more on driving access through queue signaling. In particular, we maintain two condition variables: safe_read and safe_write. If it’s safe to read, we signal the safe_read queue. Meanwhile, if it’s safe to write, we signal the safe_write queue.

From a reading perspective, not much has changed. If there is any active writing, readers are expected to wait. Otherwise, they read. When readers are finished reading, they are expected to decrement their reader count. As with the concurrent readers solution, the last reader is responsible for signaling the next writer.

From a writing perspective, a lot has changed. In addition to a new shared variable called writing, we now have two procedures instead of one: begin_write and end_write.

The begin_write procedure is responsible for verifying that it’s safe to write (i.e. no one else is reading, and there are no readers). If it’s not safe to write, writers are expected to wait. Otherwise, they indicate that they’re writing before writing.

Meanwhile, the end_write procedure indicates that writing has finished. If there are any readers waiting, writers are responsible for signaling them (aka readers’ priority). Otherwise, they signal another writer.

To me, while more complex, this solution seems a lot more intuitive than the semaphore solution. In particular, we have direct communication between processes which seems more like how we would perform a task like this in our daily lives.

Related Problems

In this article, we focused on two process synchronization mechanisms, semaphores and monitors, and how they can be used to solve a few versions of the Readers-Writers problem. In addition to the problems covered in this article, there are handful of related problems including:

  • Writers’ priority
  • Smallest job first
  • Alternating readers and writers
  • Limiting concurrent readers

And, I’m sure there are many more. In the interest of time, I chose not to solve these problems. However, if you’re interesting in learning more about these topics, I’d be happy to expand this list.

Want to Learn More?

At this point, I’m now through three topics I need to study for this qualifying exam. For now, I’m going to continue slogging through operating systems. However, at some point, I’m really going to need to tackle algorithms.

In the meantime, you can help me grow this site by becoming a member. Members are automatically added to the mailing list, and they gain access to extra content like blog articles.

If you’re looking for recommendations of related material, check out some of the following books:

I can’t personally endorse any of these books, but I have verified their relevance to process synchronization. In addition, both books are highly rated, and the reviews are solid. For instance, John Robertson gave the Java Concurrency in Practice book a 5-star review with the following testimony:

This book is really an important book for multithreaded programming. Even if you never touch Java, if you used multiple threads you really ought to make sure you know the pitfalls this book covers.

If books aren’t your thing, you’re always welcome to browse some of my favorite articles on this site:

As always, thanks for stopping by!

The post Solutions to the Readers-Writers Problem appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/code/solutions-to-the-readers-writers-problem/feed/ 0 17172
Understanding Process Synchronization https://therenegadecoder.com/code/understanding-process-synchronization/ https://therenegadecoder.com/code/understanding-process-synchronization/#respond Mon, 15 Jul 2019 14:00:00 +0000 https://therenegadecoder.com/?p=17134

With an operating systems exam in the fall, I've decided to take a look at some of the concepts I'll need to know. Up first, process synchronization!

The post Understanding Process Synchronization appeared first on The Renegade Coder.

]]>

As I further my quest in studying for the qualifying exam, I figured I’d step away from algorithms a bit and focus on something I’m quite a bit more comfortable with: process synchronization. In particular, I want to talk about the three main forms of process synchronization: locks, semaphores, and monitors.

Table of Contents

Process Synchronization Overview

At a high level, it’s important to understand why we need process synchronization. Or rather, what’s wrong with having asynchronous processes?

In general, there’s nothing wrong with asynchronous processing. In fact, in many cases, it’s ideal. After all, you and I are currently performing different tasks simultaneously, and it’s working out fine.

However, in computer systems, asynchronous processes sometimes need access to the same information. If that information is read-only, there aren’t really any issues. That said, if multiple processes are able to edit that information, there can be issues of data consistency.

A common example would be to have two processes that want to manipulate the same variable in shared memory. For instance, let’s say both processes are executing the same program where x is a shared variable:

y = x  # Read
x = y + 1  # Write

What is the final value of x if x starts at 5? Well, if the processes happen one after another as we’d hope, then x stores 7. However, x could also be 6. After all, what happens if both programs read x at the same time? Let’s take a look:

Process A: y = x  # x = 5
Process B: y = x  # x = 5
Process A: x = y + 1  # x = 6
Process B: x = y + 1  # x = 6

Obviously, we don’t want this sort of ambiguity, so we introduce something called process synchronization. Throughout the rest of this article, we’ll discuss a few mechanism for dealing with this problem. Naturally, much of the examples are borrowed from The Ohio State University’s CSE 6431 lecture notes:

That said, the analysis is strictly my own.

The Critical Section Problem

The problem outlined in the overview is known as the critical section problem. In particular, the critical section is any section of code which accesses a shared variable. In the example above, x was a shared variable, and both the processes were trying to read it then write to it.

As demonstrated in that example, we can run into a race condition where a process beats another process to a shared variable before the slower process has a chance to finish its action. Of course, race conditions are undesirable because they make a program nondeterministic.

To deal with the critical section problem, we usually resort to some form of atomicity and mutual exclusion. In other words, we want to make sure that any accesses performed on a shared variable are done so in a safe way. Using the previous example, we want process A to complete its critical section before process B enters its critical section (i.e. no interleaving commands).

To solve the critical section problem, we can use a handful of mechanisms which will be described in the remainder of this article.

Process Synchronization Mechanisms

Up to this point, we’ve talked about why process synchronization is important. Now, we’re going to discuss how it’s accomplished. In the following subsections, we’ll lay out three of the common process synchronization mechanisms.

Locks

If we wanted to remove the race condition from our original example, how would we do it? Perhaps we could introduce some sort of loop that waits on yet another shared variable called a lock:

while lock == 1: pass
lock = 1
y = x  
x = y + 1  
lock = 0

Here, we’re trying to add a layer of protection between the processes. If process A grabs the lock first, process B will be stuck waiting until process A sets lock back to zero.

That said, isn’t there still a race condition? Absolutely! Let’s say both processes manage to grab the lock at the same time. Then, they both would execute the critical section. So, what do we do?

As it turns out, just about every processor today has some form of locking mechanism which we can use in this situation. In particular, that mechanism is called test-and-set, and we can use it to rewrite our code above:

while test-and-set(lock) == 1: pass
y = x  
x = y + 1 
lock = 0

While this might not look much different, we’re actually guaranteed proper process synchronization because test-and-set is an atomic operation. In other words, there is no race condition—only one process can ever acquire the lock.

While these sort of busy locks are simple, they are wasteful. In particular, busy waiting with loops can waste a lot CPU cycles. Fortunately, there are other methods of process synchronization.

Semaphores

Instead of using locks, we could use semaphores which are integers with a little extra functionality. In particular, they have two atomic operations: P(S) and V(S) where S is the semaphore.

On one hand, P(S) decrements S as long as S is greater than zero. In addition, if P(S) decrements S, then the process that called P(S) continues executing. Otherwise, the process is blocked and placed in a queue to wait.

On the other hand, V(S) checks if there are any processes waiting on the queue. If there are, V(S) unblocks one of those processes. Otherwise, V(S) increments S.

As we can probably imagine, we can use a semaphore to then protect a critical section by wrapping it in these two function calls:

P(mutex)
y = x  
x = y + 1 
V(mutex)

Here, we are assuming that our mutex (mutual exclusion object) starts with a value of one. Whichever process acquires the mutex first is free to execute its critical section. Meanwhile, the other process is blocked until the first process exits its critical section.

Incidentally, we could have any arbitrary number of processes running concurrently and this solution would protect our critical section. That said, semaphores are tricky to use and difficult to test.

Monitors

Like semaphores, monitors also provide mutual exclusion with an added layer of abstraction. In particular, monitors consist of shared data and a set of procedures. In order to interact with the shared data, the process must use the defined procedures which are protected through mutual exclusion. In other words, only one process can interact with the monitor at a time.

Also like semaphores, monitors introduce condition variables which support two operations: wait and signal. In addition, each condition variable has its own queue which can be used to check if any processes are waiting.

Naturally, wait causes the current process to stop processing. Once stopped, the process is added to that condition variable’s queue. Meanwhile, signal tells the next process in that condition variable’s queue to begin executing.

In practice, we’d need to define some condition variable as well as a set of procedures. However, for our simple case, we don’t even need a condition variable. After all, monitor procedures guarantee mutual exclusion:

procedure increment(x):
    y = x  
    x = y + 1 

In a future article, we’ll look at a few problems like readers-writers and producers-consumers where the condition variables are necessary for tracking available resources.

Want to Learn More?

At this point, I’m two topics into studying for the qualifying exam. If you felt like anything was unclear, that’s probably because I don’t understand it well enough for this exam, so feel free to share your feedback.

If you loved it, great! Show some love by sharing your thoughts in the comments or by becoming a member. You can also show your support by hopping on the email list (included with the membership) or by purchasing one of the following related books:

As always, I don’t necessarily endorse the products listed above, but purchases made after clicking the links do earn me a commission. At the very least, I try to pick highly rated products that are relevant to the article. If you have any recommendations for good products, let me know in the comments.

If books aren’t your thing, why not continue browsing the site a bit? Below are a few articles that I think you might enjoy:

At any rate, thanks for taking some time out of your day to support the site!

The post Understanding Process Synchronization appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/code/understanding-process-synchronization/feed/ 0 17134
Understanding the Number Theory Behind RSA Encryption https://therenegadecoder.com/code/understanding-the-number-theory-behind-rsa-encryption/ https://therenegadecoder.com/code/understanding-the-number-theory-behind-rsa-encryption/#respond Fri, 12 Jul 2019 14:00:43 +0000 https://therenegadecoder.com/?p=16947

Kicking of studying for the qualifying exam with a bit of number theory as the basis of RSA encryption. Wish me luck!

The post Understanding the Number Theory Behind RSA Encryption appeared first on The Renegade Coder.

]]>

With my qualifying exam coming up in a couple months, I figured I could document some of the things I’ll be studying. For instance, as a part of my algorithms course, I learned RSA encryption. Unfortunately, the algorithm alone is pretty complicated, but I’m also responsible for understanding the number theory behind it. Time to brush up on my modular arithmetic!

Table of Contents

RSA Encryption Overview

Before we get into the details, I figured we could start by talking about what RSA encryption is and how it works at a high level.

RSA encryption—which comes from the names of the inventors: Rivest, Shamir, and Adelman—is a method of encryption which relies on a trapdoor one-way function to generate a pair of keys for data encryption. One key is known as the private key, and it’s kept hidden for personal use. Meanwhile, the other key is known as the public key, and it’s distributed to anyone who might use it.

In tandem, these keys are used to exchange encrypted messages between individuals. For example, if I wanted to send you a message, I would encrypt it using your public key. To read it, you would decrypt it using your private key. Naturally, once the message is encrypted with the public key, only the private key can be used to decrypt it and vice versa.

In the case of RSA, the one-way function which is used to generate the keys is derived from the difficulty of prime factorization, the ability to decompose a number into its prime factors. In other words, RSA encryption ensures that it is easy to generate a pair of keys, but it’s very hard to figure out one of the keys given the other.

Regardless, in the following sections, I’ll cover a bit about the number theory behind RSA encryption, and I’ll cover the actual RSA encryption algorithm. A lot of this content is borrowed from The Ohio State University’s CSE 6331 lecture notes, but all the analysis is strictly my own.

Number Theory Background

To understand the algorithm behind RSA encryption, it’s helpful to have a little bit of background in number theory.

Modular Arithmetic

Much of RSA encryption is built off of modular arithmetic which uses a number system comprised of integers that wrap around at some limit. For most developers, modular arithmetic is practically second nature as integers in most programming languages have limits. However, the math behind the concept is significantly more complex.

Before we get into any of that fun stuff, let’s talk about the modulo operator. In many languages, the modulo operator is the percent sign (%). Most older languages don’t have a true modulo operator. Instead, they have a remainder operator. The difference is subtle, but it is one that matters.

With a true modulo operator, the modulus defines the range of values that you can cycle through. For example, 13 % 5 would be 3 because 13 cycles around 5 twice before settling on 3—like a clock with only five ticks (1, 2, 3, 4, 5 (0)). Coincidentally, 13 divided by 5 also has a remainder of 3, so it’s no surprise that the operations get confused.

That said, things get interesting when negative numbers are introduced. For instance, 13 % -5 would be -2 whereas the remainder would still be 3. In the case of modulo, we’ve defined a new cycle which contains only negative values (-5 (0), -4, -3, -2, -1).

For my own sanity, I actually tested a few of these in Python (true mod) and in Java (remainder). Here are the results:

>>> 17 % 4
1
>>> 17 % -4
-3
>>> -17 % 4
3
>>> -17 % -4
-1
> 17 % 4
1
> 17 % -4
1
> -17 % 4
-1
> -17 % -4
-1

With modular arithmetic, we get four distinct answers—one for each cycle orientation and direction. Meanwhile, remainder only gives us two—one for each dividend.

Congruence

While modular arithmetic alone isn’t all that interesting, it has some fun properties. In particular, we can start talking about congruence. To do that, we should probably cover a new convention called divides.

In mathematics, we show that a divides b with a new symbol: |. For example, 3|9 states that 3 divides 9. While it’s a simple symbol, we can use it to define congruence.

Now, a is congruent ( ≡ ) to b mod n if n|(a-b). In other words, a and b have the same “remainder” when divided by n. For example, 121 ≡ 16 mod 7 since both values have a remainder of 2 when divided by 7.

With this congruence relationship, we’re able to come up with some pretty interesting properties of modular arithmetic. For example, a ≡ a mod n since a and a have the same “remainder” when divided by n. We call this the reflexive property.

In addition to the reflexive property, there is also the symmetric property which states that a ≡ b mod n is equivalent to b ≡ a mod n. Finally, we have the transitive property which states that if a ≡ b mod n and b ≡ c mod n then a ≡ c mod n.

Together, these three properties demonstrate that congruence modulo n is an equivalence relation. We can then use this relationship to begin grouping values that are congruent into sets: [a]n = {x ∈ Z : x ≡ a mod n}. For example, modulo 2 creates two sets of numbers: evens ([0]2) and odds ([1]2). These sets are called residue classes where a residue can be thought of as another word for remainder.

Groups

Unfortunately, there’s still quite a bit of number theory to slog through before we can really dig into the encryption algorithm. For instance, it’s important to explore the concept of groups.

At a high level, a group (G) is a set in which a binary operator (*) can be used to combine two elements into a third element. However, the relationship between the three elements must follow four conditions: closure, associativity, identity, and inverse.

  • Closure: ∀x,y ∈ G, x*y ∈ G (in words, for all x and y in G, the result of x * y is also in G)
  • Associativity: x*(y*z) = (x*y)*z
  • Identity: ∃e ∈ G s.t. ∀x ∈ G, e*x = x*e = x (in words, there exists an element e in G such that for every element x the equation holds)
  • Inverse: ∀x ∈ G, ∃y ∈ G s.t. x * y = y * x = e (in words, for every x in G, there exists a y in G such that performing the binary operation between the elements produces the identity element)

One example of a group is the set of all integers and the addition operator or (Z, +). Likewise, the same can be said for the set of all rational numbers, (Q, +), and the set of all real numbers, (R, +).

Residue Class Groups

With what we know about residue classes and groups, we can start to define groups of residue classes like the one bound by addition, (Zn, +). Specifically, Zn is defined as a set containing all the residue classes modulo n (i.e. {[0], [1], [2], ..., [n - 1]}).

First, however, we should define a few operations for residue classes. As it turns out, residue classes have a simple property: they can be added and multiplied directly. In particular, if x ∈ [a], y ∈ [b], then x + y ∈ [a + b] and x ⋅ y ∈ [a ⋅ b].

Now, is addition enough to constitute a group? As it turns out, yes. After all, it checks all four boxes:

  • Closure: integer addition already passes this criteria
  • Associativity: ditto!
  • Identity: like integer addition, 0 is our identity element
  • Inverse: again, integer addition defines -a as the inverse

Unfortunately, (Zn, ⋅ ) is not a group since 0-1 does not exist. To make matters worse, some inverses don’t exist even when the set of integers is strictly positive. In particular, we define the inverse such that for a ∈ Zn, a-1 exists iff gcd(a, n) = 1 where gcd is the greatest common divisor. In other words, a must be relatively prime to n.

Naturally, the next step would be to define a new set of residue classes which only contains relative primes to n. We call this set Zn* and it is defined as follows: {a ∈ Zn : gcd(a, n) = 1}. An example of this set would be Z12* which contains 1, 5, 7, and 11—all the relative primes to n between 0 and 11.

Now, is this new set enough to form a group with multiplication? Once again, yes! In particular, the associativity and identity properties follow multiplication. In addition, we can compute the inverse using the Extended Euclidean Algorithm. It’s the closure property which I find the most interesting. Somehow, a ⋅ b (mod n) is always in the set.

Cardinality

Next, an interesting property of sets and groups is cardinality: the size or number of elements (|S| where S is some set). With a typical set of modulo n residue classes, we have exactly n elements. How do we go about measuring the cardinality of our set of relative prime residue classes?

As it turns out, the cardinality of our set Zn* can be measured using Euler’s Totient function. There are two ways the function is used:

  1. φ(pe) = (p – 1)p(e-1) for prime p
  2. φ(ab) = φ(a)φ(b) if gcd(a,b) = 1

Knowing this fact, we can actually compute the cardinality for any n in Zn*. For example, let’s say n is 15. Then, φ(15) = φ(5)φ(3) = 4 ⋅ 2 = 8. Now, let’s see if we can list them all: {1, 2, 4, 7, 8, 11, 13, 14}.

Interestingly, there are a few properties that come out of knowing the cardinality of Zn*. For example, Langrange’s theorem shows that for any a in our group, a to the power of the cardinality of that group is equal to the identity of that group (a ∈ G, a|G| = e). From the example above:

28 mod 15 = 1.

As a corollary to that property, a to the power of some m is equal to a to the power of m mod the cardinality of G (a ∈ G, am = am mod |G|). Again, using the example above:

257 = 257 mod 8 = 21 = 2.

On top of that, Euler’s theorem states that for any a in Zn*, a to the power of the cardinality of Zn* is 1 (a ∈ Zn*, aφ(n) = 1). Using our example from above again:

78 mod 15 = 1.

Finally, Fermat’s Littler Theorem states that if a is in Zp* where p is a prime, then a to the cardinality of Zp* is equal to a to the power of p minus 1 or 1 (a ∈ Zp*, aφ(p) = ap-1 = 1). Using a new example where p is 11:

7φ(11) = 710 = 1.

RSA Encryption Algorithm

Given our new background in number theory, the RSA Encryption algorithm should be pretty straightforward.

Step 1: Choose Large Primes

To start, the first thing we want to do is pick two very large primes (>= 2048 bits). We want to do this because prime factorization is a very difficult task. While it’s extremely easy to multiply two primes to create a composite value, it’s much more difficult to figure out which two primes created that composite value (aka a one-way function).

Unfortunately, finding large prime numbers is not a trivial task. To do so, we generally use some form of guess-and-check method. In other words, we generate some large number of our desired length and test if it’s prime.

To test if a value is prime, we can brute force divide the value by all numbers between 2 and the square root of the value. Of course, this process is slow for the types of large values we’d like to test, so it would be nice if there were a better method.

Enter: the Fermat Test. Previously, we stated that if n is prime, then for any a: an-1 = 1 (mod n). In other words, pick a random a between 1 and n-1 and solve the equation. If the result is 1, we probably have a prime. However, there are composite values which pass this test, and they’re known as Carmichael Numbers.

To improve on the Fermat Test, the Miller-Rabin Test was born. In addition to computing the Fermat Test, the Miller-Rabin Test adds an additional probabilistic test which further rules out Carmichael Numbers. In the future, I might dig into that algorithm much deeper.

At any rate, with the two prime numbers (p and q) picked, we’ll want to compute n as the product of p and q.

Step 2: Compute the Encryption Keys

From n, we need to select the first encryption key, e. We do this by selecting a value between 1 and the cardinality of Zn* (aka φ(n)). As an additional criteria, e must be coprime to φ(n).

As an example, consider two small prime numbers: 13 and 23. In this case, n is p ⋅ q = 13 ⋅ 23 = 299. From there, φ(n) is simple to compute: (p – 1)(q – 1) = (12)(22) = 264. In other words, we need to select an e between 1 and 264 that is also coprime to 264. For the sake of simplicity, we’ll select some small prime number that doesn’t divide into 264. How about 19?

With e, we can compute the decryption key, d, as follows: d = e-1 mod φ(n). In other words, ed ≡ 1 mod φ(n). To do this, we can use Euclid’s Extended Algorithm, but for simplicity let’s use this Modular Multiplicative Inverse calculator. In this case, d = 139.

Step 3: Profit

With our two constant, we can begin encrypting and decrypting messages. To do that, we need to distribute our public key. By convention, we’ll use d in combination with n (139, 299) as our private key and e in combination with n (19, 299) as our public key.

From there, if someone wants to send us an encrypted message, they’ll take our public key and encrypt their message with it. For simplicity, they might take each character in the message and convert it to its ASCII value (m). Then, they’ll apply the public key to that value as follows: c = me mod n. When we decrypt that value, we’ll use the same function except e will be replaced by d (since they’re inverses): m = cd mod n.

Since we distribute n alongside e, we have to ensure that n is sufficiently large. Otherwise, someone can easily reduce n to its prime factors and compute d. As of today, the industry standard requires an n greater than 2048 bits.

Want to Learn More?

In the process of writing this article, I realized that I wasn’t going to be tested on it, so I stopped putting so much effort into it. As a result, there may be concepts you still want to explore like primality testing. Likewise, you probably want to see more concrete examples. Unfortunately, at this time, I won’t be able to provide any additional support.

However, if there’s enough interest, I may expand this article or write an additional article clarifying anything you’d like to know. As someone who struggles with the math side of Computer Science, I’m not sure how much help I can be, but I’m always willing to try!

In the meantime, help me make this feel like less of a waste of time by subscribing either as a member or through the email list. In addition, you might be interested in some of these algorithm and cryptography books available on Amazon:

To be honest, I don’t endorse these books. However, by following the link and making a purchase, I’ll receive a small commission which helps grow the site.

If books aren’t your thing, but you’re interested in topics related to RSA Encryption, then check out some the following articles:

Thanks again for your support!

The post Understanding the Number Theory Behind RSA Encryption appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/code/understanding-the-number-theory-behind-rsa-encryption/feed/ 0 16947
What is a Programming Language? https://therenegadecoder.com/code/what-is-a-programming-language/ https://therenegadecoder.com/code/what-is-a-programming-language/#respond Mon, 08 Jul 2019 14:00:27 +0000 https://therenegadecoder.com/?p=16955

As someone who is just about sick of the gatekeeping in tech, I figured it was time to write a little bit about the definition of a programming language.

The post What is a Programming Language? appeared first on The Renegade Coder.

]]>

When most of us think about programming languages, we think about popular languages like Python, C#, and JavaScript, but where do we draw the line? In this article, I want to push the boundaries on conventional wisdom by challenging a few common arguments like the one that inspired this article: HTML and CSS are not programming languages.

Table of Contents

Inspiration

To be honest, I hadn’t really put any thought into what makes a programming language in the past. After all, we just write code, and that can take many forms. Who is to say what is and isn’t a programming language?

As it turns out, there’s quite a heated debate in the web development world about whether or not HTML and CSS are programming languages. In fact, I stumbled upon this debate over on dev.to where Desi kicked off a discussion on the topic.

Thankfully, that platform rarely breaks out into a flame war, so you can find a lot of gold nuggets in a discussion like that. Of course, I figured I’d chime in:

Personally, I would say yes [that HTML and CSS are programming languages], but my definition of a programming language is more fluid. For instance, you could ask a similar question for esoteric languages like brainf*ck or data languages like yml or json. As long as the content of the text is being interpreted/compiled by a computer, it’s a programming language.


Now, there are definitely levels to this as some languages can accomplish a lot more than others, but that’s a different discussion.

In terms of experience, I’ve taken a few classes and even written a compiler for a toy language as well as a Lisp interpreter. Now, I just maintain the Sample Programs repository (shameless plug) which contains 106 languages at the time of writing.

After making that comment, I got to thinking more about what makes something a programming language, so I decided to share some of my thoughts.

Programming Language Definitions

If you search the internet for the definition of a programming language, you’ll find a lot of word soup. For instance, Wikipedia states that “a programming language is a formal language, which comprises a set of instructions that produce various kinds of output.” Meanwhile, TechTerms describes a programming language as “a set of commands, instructions, and other syntax use to create a software program.” Hell, here are a few more definitions:

  • Computer Hope: “A programming language is a special language programmers use to develop software programs, scripts, or other sets of instructions for computers to execute.”
  • Merriam Webster: “any of various high-level languages used for computer programs”
  • Webopedia: “A programming language is a vocabulary and set of grammatical rules for instructing a computer or computing device to perform specific tasks.”

Is there any sort of unified thread that we can extract from these definitions? In other words, can we come up with any sort of criteria for language categorization based on these definitions? To me, it seems like we just need a couple things to be able to call something a programming language:

  • Syntax (i.e. a grammar composed of instructions, commands, etc.)
  • Semantics (i.e. some meaning given to that grammar)

Oh, and we should probably be able to run that language on a computer. Now, let’s see just how far we can stretch that definition.

Examining Various Languages

When considering whether or not something is a programming language, it doesn’t do us a lot of good to look at languages that typically fit the bill. Instead, I want to look at languages that are on or just beyond the edge like CSS and HTML.

MATLAB

To be honest, MATLAB probably seems like a weird place to start when challenging ideas of what is and isn’t a programming language. After all, it’s obviously a programming language, right?

If you’ve never heard of MATLAB, it’s essentially a tool used by engineers and data scientists to run simulations and make visualizations. And like most programming languages, it has a very clear syntax and semantics:

sum1 = 0;
sum2 = 0;
N = 27
for k = 1:N
  sum1 = sum1 + k;
  if (mod(k, 7) == 0)
    sum2 = sum2 + k;
  end
end

To the casual observer, this looks like programming—and it is! Yet, a lot of programming purists look down on MATLAB. Since it’s not used to create applications, it’s not a real programming language.

Of course, MATLAB is absolutely a programming language based on our agreed definition above, and it bothers me that there’s a very vocal minority excluding MATLAB programmers from being real programmers. For instance, some of my mechanical engineering friends use MATLAB all the time to simulate their designs. Are they not programmers at least in some capacity?

HTML

If you’re not familiar with HTML, it’s a markup language which is usually used to specify the structure of a web page. Specifically, it’s a tree-like language where the document has a root node (i.e. <html>) which can contain any number of child nodes (i.e. <head>, <body>, etc.). Naturally, these children may have children and so on.

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Hello, World!</title>
  </head>
  <body>
    <h1>Check Out This Heading</h1>
  </body>
</html>

Now, HTML usually hits a snag in the programming language debate because it doesn’t perform any action; it’s static. In other words, there is no flow control. Instead, HTML relies on the browser to interpret and display it.

That said, there is still quite a bit of logic that goes into constructing an HTML document. Understanding how a browser is going to render the HTML is no different than understanding how the JVM is going to run a Java program. In both cases, the developer is programming.

If you don’t buy that logic, at the very least, HTML hits all the hallmarks of our definition. In particular, it has a clearly defined syntax, and that syntax has a clearly defined meaning to a browser (which happens to be on a computer).

CSS

Along with HTML, you’ll often find an interesting language called CSS. To the best of my knowledge, CSS is used to style HTML by applying properties to nodes.

h1 {
  display: block;
  font-weight: bold;
  background-color: red;
}

In combination with HTML, CSS can actually be used to drive logic from user interaction. In other words, buttons can be used to change the state of the web page using only HTML and CSS. To me, that sounds like a programming language.

Of course, CSS hits a snag because of its dependency on HTML. Alone, it doesn’t really do much. That said, I think that’s sort of a silly comparison because that’s true for all programming languages (i.e. Java is nothing without the JVM). All languages require other software—or at least hardware—to give it meaning.

As a result, I think CSS fits nicely within the bounds of our programming language definition. After all, it has clear syntax and semantics (per browser), and it happily runs on a computer.

SVG

Now, we start to get into some serious gray area: data formats. In this case, I want to talk about formats like JSON, XML, SVG, and even CSV and Markdown. Are these programming languages? I’m going to argue yes.

Let me start by asking a question: have you ever tried to write an SVG? If you have, then you know how challenging that can be:

<svg height="210" width="500">
  <polygon points="200,10 200,190 120,210" style="fill:purple;stroke:aqua;stroke-width:2" />
</svg>

In this case, we’ve drawn a triangle which can be interpreted and drawn by any number of tools that can understand the SVG format (i.e. the browser). In other words, SVG is a programming language since it has a clearly defined syntax that gains meaning from certain environments like the browser.

XML

If HTML and SVG are programming languages, then surely XML is a programming language. Well, that’s a bit harder to prove.

<CATALOG>
  <CD>
    <TITLE>Empire Burlesque</TITLE>
    <ARTIST>Bob Dylan</ARTIST>
    <COUNTRY>USA</COUNTRY>
    <COMPANY>Columbia</COMPANY>
    <PRICE>10.90</PRICE>
    <YEAR>1985</YEAR>
  </CD>
  <CD>
    <TITLE>Hide your heart</TITLE>
    <ARTIST>Bonnie Tyler</ARTIST>
    <COUNTRY>UK</COUNTRY>
    <COMPANY>CBS Records</COMPANY>
    <PRICE>9.90</PRICE>
    <YEAR>1988</YEAR>
  </CD>
</CATELOG>

While XML has a clearly defined syntax, its meaning is a lot less clear. After all, XML, like JSON, is largely used to carry data, so it only derives meaning under certain circumstances like as an SVG.

However, because so many tools depend on XML as a configuration format (see Maven), XML should be considered a programming language by extension. In other words, XML derives meaning only with context, but that doesn’t make it any less of a programming language. After all, Python doesn’t make any sense to GCC, but we still consider it a programming language.

JSON, CSV, etc.

Since we’re on the subject of data formats, how about JSON, CSV, and Markdown? All of them have a clearly defined syntax, but can we derive any meaning from them? Naturally, the answer is yes:

{  
   "menu":{  
      "id":"file",
      "value":"File",
      "popup":{  
         "menuitem":[  
            {  
               "value":"New",
               "onclick":"CreateNewDoc()"
            },
            {  
               "value":"Open",
               "onclick":"OpenDoc()"
            },
            {  
               "value":"Close",
               "onclick":"CloseDoc()"
            }
         ]
      }
   }
}

In this case, I’ve chosen to share a sample JSON which should be reminiscent of XML (implying that JSON is indeed a programming language). Of course, like XML, JSON derives meaning from context. For example, JSON might also be used for configuration files. In fact, I’ve seen a similar language, YAML, used exactly for that when setting up continuous integration platforms like Travis CI. Is that configuration file not a form of programming?

Similarly, CSV is a data format that doesn’t have any meaning on its own. Like XML, JSON, YAML, and even HTML, CSV relies on a program to interpret it. Is that not what Microsoft does with Excel? How about Google Sheets? These are programs that interpret and display CSV data which gives that data meaning.

Finally, Markdown is a text formatting language which is often used to generate HTML for web pages. Does that make it less of a language because it simplifies a process? I’m sure this is the same argument that was made about higher-level languages like Python and Java by folks who refused to move on from COBOL and FORTRAN. In other words, the art of gatekeeping.

Sheet Music

Now, we’re starting to get into muddy water, but hear me out: sheet music may as well be a programming language.

Handwritten Sheet Music

When I decided to write this article, I was actually sitting in a rehearsal. At the time, I was thinking about how some of the ways that we annotate music are ambiguous. For example, the director stated that we should play one of the quarter notes short like an eighth note which prompted one of the sax players to question what the director meant by that. Did he want an eighth note followed by an eighth rest? How about a dotted quarter note?

At any rate, that’s when I got to thinking: is sheet music a programming language? After all, a composer is really just a programmer trying to get the right combination of sounds out of an ensemble through a language with a certain syntax (like Common Music Notation) and semantics.

In fact, Common Music Notation has all sorts of mechanisms that mirror control flow in popular programming languages. For example, there are repeat signs which work similar to loops, double bars which tell the musicians when to stop, and measure numbers which are reminiscent of line numbers.

Of course, we sort of hit a snag in our original definition. After all, sheet music is interpreted and ran by musicians, not computers. Also, I don’t think musicians would appreciate being called computers, but I don’t think the comparison is that far off.

Classification of Programming Languages

At this point, we’ve looked at a lot of languages and tried to come up with some argument over whether or not they are a programming language. Due to the overwhelming lack of a concrete definition of a programming language, I’m willing to argue that just about anything that has a formal syntax and a derived meaning can be considered a programming language. However, not all programming languages are the same.

In general, there are a handful of programming language categories: imperative, functional, structural, declarative, etc. Today, we’ve sort of blurred the lines between these categories thanks to multi-paradigm languages. That said, I still think these categories serve an important purpose in at least proving the case that languages like HTML, XML, and JSON are truly programming languages.

Most of the languages that people tend to describe as not programming languages—HTML, CSS, XML, etc.—are really declarative programming languages. In other words, we use these languages to declare what we want our system to do, not how.

To rub a little salt in the wound, Wikipedia actually lists quite a few declarative programming languages including Make, SQL, HTML, and Prolog. In fact, regular expressions are considered a declarative programming language. How’s that for stretching the bounds of the definition of a programming language?

What is a Programming Language?

If I can make the argument that sheet music is a programming language, then why are we even still debating what is and isn’t a programming language?

Now, that’s not to say that programming languages don’t deserve to be categorized. After all, there’s some merit in that. However, it bothers me when we try to put each other down by saying things like “you’re not a real programmer because you code in x.”

At the end of the day, who cares what someone else codes in? We’re talking about tools here, and I don’t think I’ve ever heard anyone put down for using any of the following tools:

  • Pencil (Wow, I can’t believe you’re using a #2 pencil.)
  • Hammer (DeWalt? Really?)
  • Calculator (TI-84? Try TI-86, loser!)

See how silly all that sounds? Just let people code, will ya?

As always, thanks for taking some time out of your busy lives to support my work. In addition to coding, I love to write, and I hope content like this helps someone out. If you like this article, make sure to give it a share. Also, consider becoming a member or at least hop on the mailing list, so we can stay in touch. While you’re here, why not take a look at some of these other articles:

Well, that’s it for now! Thanks again.

The post What is a Programming Language? appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/code/what-is-a-programming-language/feed/ 0 16955
Preparing for the Qualifying Exam https://therenegadecoder.com/blog/preparing-for-the-qualifying-exam/ https://therenegadecoder.com/blog/preparing-for-the-qualifying-exam/#respond Fri, 05 Jul 2019 14:00:04 +0000 https://therenegadecoder.com/?p=16932

With just two months to go before my qualifying exam, I figured it was time to start talking about how I'm going to study for it. Wish me luck!

The post Preparing for the Qualifying Exam appeared first on The Renegade Coder.

]]>

With my qualifying exam coming up in August, I thought it would be fun to talk about how I’m preparing. After all, I’m terrible at tests, so I figured it might be worth taking things a bit more seriously this time around.

Table of Contents

Qualifying Exam Logistics

From my understanding, the qualification exam is a test that forces me to retake three finals at once. Those three topics are based on the core classes I chose in my first year of the program: algorithms, programming languages, and operating systems. Or, as the department website states it:

The Qualifying Examination is based on the material covered in the graduate core areas. Specifically, students need to take the exam in algorithms, either computability and unsolvability or programming languages, and either operating systems or computer architecture.

At this time, I have literally no idea what to expect, and it’s making me kind of nervous. After all, I haven’t been good at studying or taking tests since I got back from industry. In addition, some of the topics are way out of my wheelhouse like proving graph theory in algorithms. In fact, I’m extremely worried about the algorithms portion of the exam. The other two topics are a bit of a tossup.

How to Study for the Qualifying Exam

Here’s my plan. I’m going to launch a new set of posts that target each of the areas that that I’m most worried about. Since the topics are going to be mostly unrelated, I won’t be making a special series for them. However, I do plan to link them here as each new article is published.

In particular, these are topics I plan to study—and hopefully write about:

  • Dynamic Programming
  • Greedy Algorithms
  • Graph Theory
  • RSA Encryption
  • Mutual Exclusion
  • Deadlock Prevention and Avoidance
  • Attribute Grammars
  • Lisp

Of course, I’m sure I’ll dig up plenty more topics as I start studying. That said, I wanted to make sure I had a plan set out. With just two months to go before the exam (at the time of writing), I want to be more prepared than ever.

Wish Me Luck

Usually, I’d write a much longer article, but I don’t really have much else to say. All I know is that I have to get to work if I want to pass this exam. If all goes well, a major weight will be lifted again. In other words, wish me luck!

If you haven’t been following me on this journey, I recommend checking some of the posts that talk about how I got this far:

If you’re reading this post, you’re already a member. That said, I’d appreciate it if you shared this post with your friends. I could use the support!

The post Preparing for the Qualifying Exam appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/blog/preparing-for-the-qualifying-exam/feed/ 0 16932
Why Do We Reward Overwork? https://therenegadecoder.com/blog/why-do-we-reward-overwork/ https://therenegadecoder.com/blog/why-do-we-reward-overwork/#respond Mon, 01 Jul 2019 14:00:10 +0000 https://therenegadecoder.com/?p=16881

Living in a society that values hard work can be challenging, but sometimes it goes to far. Today, I ask: why do we reward overwork?

The post Why Do We Reward Overwork? appeared first on The Renegade Coder.

]]>
To view this content, you must be a member of Jeremy Grifski's Patreon at "For Glory!" or higher tier

The post Why Do We Reward Overwork? appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/blog/why-do-we-reward-overwork/feed/ 0 16881
The Difference Between Statements and Expressions https://therenegadecoder.com/code/the-difference-between-statements-and-expressions/ https://therenegadecoder.com/code/the-difference-between-statements-and-expressions/#comments Fri, 28 Jun 2019 14:00:44 +0000 https://therenegadecoder.com/?p=16633

Today, I want to talk about the difference between statements and expressions in Computer Science and why ignoring that distinction has consequences.

The post The Difference Between Statements and Expressions appeared first on The Renegade Coder.

]]>

As I grow more interested in programming languages—and languages in general—I find that the theory doesn’t always match up with reality. For instance, I just learned about the difference between statements and expressions and how that difference isn’t always explicit in modern programming languages.

Table of Contents

Background

As a current PhD student and Graduate Teaching Assistant, I’ve been focusing a lot on what it takes to be a good professor. To do that, I’ve been learning from different faculty about their experiences and philosophies. Recently, I learned about the difference between statements and expressions, so I thought that would be fun to share with you.

Oddly enough, I actually learned the distinction the hard way while training to teach a software fundamentals course. As a part of that training, I had to complete all the programming assignments, so I could get feedback from the instructor. At one point, the instructor mentioned to me that they didn’t like the following Java syntax:

a[++i]

In this case, we have an array that we’re accessing through ++i. In other words, we increment i then access a at that index—all in one line. See any problems? If not, don’t worry! That’s the topic of today’s article.

Terminology

Right out of the gate, I’d like to differentiate two terms: expression and statement. These terms will form the basis of the argument behind why a[++i] is considered bad practice.

Expressions

In Computer Science, when we talk about expressions, we’re referring to anything that can be evaluated to produce a value. Naturally, we can think of any data by itself as an expression because data always evaluates to itself:

4
"Hi!"
x
'w'
true
9.0

Of course, expressions can be made up of expressions:

4 + 2
"Hi," + " friend!"
x * y
'w' + 4
true == !false
9.0 / 3

In each of these scenarios, we use operators to nest our expressions, so we get something that might look like the following language grammar:

<expr>: number 
      | (<expr>)
      | <expr> * <expr>
      | <expr> + <expr> 

Here, we’ve created a silly grammar which defines an expression as a number, an expression in parentheses, an expression times an expression, or an expression plus an expression. As you can probably imagine, there are a lot of ways to write an expression. The only rule is that the expression must return a value.

Statements

In contrast, statements do not return anything. Instead, they perform an action which introduces some form of state (aka a side effect). The following list contains a few examples of statements:

x = 5
if (y) { ... }
while (true) { ... }
return s

If we look closely, we might notice that some statements contain expressions. However, the statements themselves do not evaluate to anything.

The interesting thing about statements is that they depend on order. To make sense of some statement, it’s important to understand the context leading up to it.

In contrast, expressions don’t depend on state since they do not produce side effects, so any nested expression can be reasoned about directly. For instance, notice how we can isolate any part of the following expression and evaluate its result:

((6 * 7) + (5 + 2 + 1)) > 17

Sure, any outer scope is going to depend on the result of some inner scope, but evaluating (6 * 7) has no effect on 17. As a result, it’s very easy to reason about the expression even when elements of it change. Welcome to the foundations of functional programming—but, that’s a topic for a different time!

What’s the Catch?

Unfortunately, while the definitions I’ve provided are clean cut, modern programming languages don’t always adhere to the same principles. For example, is ++i a statement or an expression? Trick question: it may be both.

In Java, ++i and i++ can be used as standalone statements to change the state of the program. For instance, they’re often used to increment a variable in a for loop. In addition, however, they can be used as expressions:

a[++i]
a[i++]
someFunction(i++)

In other words, ++i returns a value, and that value is different from i++. As you can probably imagine, this ambiguity between statements and expressions can manifest itself into some nasty bugs. For example, what do you think the following program does?

i = 0
while (i < 5) {
  print(i)
  i = i++
}

Without getting into the weeds, this code snippet may do many different things. In Java, it will actually print zero indefinitely despite clearly incrementing i in the 4th line. As it turns out, the postfix ++ operator returns the old value of i after increasing its value by one. In other words, i is incremented then reset to zero.

The consequences of the ambiguity between statements and expressions is immense, and it carries over into functions and procedures as well.

But Wait, There’s More

Often times, terms like methods, functions, procedures, and subroutines are all used interchangeably. In fact, you’ll probably find that I hardly differentiate between the terms on my own site. That said, there is a subtle difference at least between functions and procedures, so let’s talk about it.

Functions

Like mathematical functions, programming functions return a value given some input:

int getLength(String s) { ... }
double computeAreaOfSquare(double length) { ... }
double computePotentialEnergy(double m, double g, double h) { ... } 

In other words, the return type of a function cannot be nothing (i.e. void). As a result, functions are similar to expressions: they return a value without any side effects. In fact, they often work in the place of expressions:

(getLength(s1) * 2) > getLength(s2)

By definition, a function would then be an expression.

Procedures

In contrast, procedures do not return a value. Instead, they perform some action:

void scale(Square sq, double sc) { ... }
void insertElementAt(int[] list, int index, int element) { ... }
void mutateString(char[] str) { ... }

As a result, procedures relate more closely to statements in that they only produce side effects. Naturally, they cannot be used as expressions:

mutateString(s) * 4 // What?

By definition, a procedure would then be a statement.

Blurring the Lines

Like with expressions and statements, modern programming languages have blurred the lines between functions and procedures. In some cases, it’s not even possible to separate the two.

Consider Java which has a pass-by-value system. If we want to design a data structure, we often implement actions like add, remove, push, pop, enqueue, dequeue, etc. These actions are intuitive because they work how we expect them to work. For example, if we want to add an element to a stack, we’re going to call push with a copy of the element as input.

Now, imagine we want to implement one of the remove methods (i.e. pop). How do we go about doing it without blurring the lines between function and procedure? Clearly, pop has a side effect: it removes the top element from the stack. Ideally, however, we’d also like to be able to return that value. Since Java is pass-by-value, we can’t pass a reference to the element back to the caller through one of our parameters. In other words, we’re stuck creating a function with side effects.

As a consequence, our pop method could be used as either an expression or a statement. When used in an expression, it suddenly becomes difficult to reason about what that expression is doing because parts of that expression may see different states of the stack. In addition, successive calls to the same expression may yield different results as the state of the stack changes each call.

That said, there is one way around this problem. We could create a pair of methods, one function and one procedure, to get the top element from the stack (peek) and remove that element (pop). The idea here is that we maintain the separation between pure functions and procedures. In other words, we can use peek when we want to know what value is on the top of the stack without modifying the stack. Then, we can use pop to remove that top element.

Of course, introducing a pure function and a procedure in place of a function with side effects requires a bit of discipline that may or may not pay off. It’s up to you to decide if it’s worth the effort.

Discussion

For me, learning about the distinction between statements and expressions set off a chain reaction of questions about language design. After all, millions of people around the world are coding without any concern for these details, so my question is: does it really matter?

Lately, I’ve noticed a trend toward functional programming (FP), and I wonder if that’s a consequence of all the technical debt that’s built up from the blurred lines between expressions and statements. If not, is this trend toward FP really just hype? After all, FP isn’t new. For instance, Lisp is over 60 years old which is eons in the tech community. What are your thoughts?

While you’re here, check out some of these related articles:

Also, if you’re interested in growing the site, I have a mailing list where you’ll get weekly emails about new articles. Alternatively, you can become a full blown member which will give you access to the blog. At any rate, thanks for taking some time to read my work!

The post The Difference Between Statements and Expressions appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/code/the-difference-between-statements-and-expressions/feed/ 2 16633
How to Initialize an ArrayList in Kotlin https://therenegadecoder.com/code/how-to-initialize-an-arraylist-in-kotlin/ https://therenegadecoder.com/code/how-to-initialize-an-arraylist-in-kotlin/#respond Mon, 24 Jun 2019 14:00:30 +0000 https://therenegadecoder.com/?p=16590

As a new user of Kotlin, I wanted to write some articles like my How to Python series. To start, let's learn how to initialize an ArrayList in Kotlin.

The post How to Initialize an ArrayList in Kotlin appeared first on The Renegade Coder.

]]>

For those of you familiar with the How to Python series, I thought it would be fun to try my hand some other languages I’ve been using lately. Today, let’s learn how to initialize an ArrayList in Kotlin.

Table of Contents

Problem Introduction

As someone who came from Java, I often find myself using the ArrayList class to store data. Unfortunately, there’s no clean way of initializing an ArrayList in Java, so I wondered if Kotlin had improved on that issue. For reference, here’s what I don’t want to do:

ArrayList<Integer> list = new ArrayList<Integer>()
list.add(7)
list.add(-4)
list.add(3)

As you can probably imagine, this solution does not scale well. In fact, I don’t even think it reads well. There’s just too much redundant information. I would prefer to be able to do something like the following:

ArrayList<Integer> list = new ArrayList<Integer>(7, -4, 3)

And, for larger data sets, it would be nice to be able to spread the values over multiple lines:

ArrayList<Integer> list = new ArrayList<Integer>(
    7, -4, 3, 2, 1, 3, 6, 5, 9, 11,
    10, 7, -5, -6, 13, 6, -11, 13, 2, 1
)

Unfortunately, that’s just not the case. There are some nasty workarounds, but I was hoping Kotlin would improve on the Java conventions a bit.

Solutions

Fortunately, Kotlin has improved quite a bit on Java’s verbosity, so I promise there’s a better way to create an ArrayList. It’s just a matter of how.

Initializing an ArrayList by Brute Force

Naturally, we can translate the Java solution almost directly:

val list = ArrayList<Int>()
list.add(7)
list.add(-4)
list.add(3)

Here, we’ve created an empty ArrayList of integers. Then, we populated that list one item at a time using the add() method.

Of course, we’d love something better than this! Let’s see what Kotlin has to offer.

Initializing an ArrayList by Conversion

One way to reduce some of the code from above is to create an Array before converting it into an ArrayList:

val list = intArrayOf(7, -4, 3).toCollection(ArrayList())

In a single line of code, we’re able to create an array of integers using the ideal syntax. From that array, we can obtain an ArrayList using the toCollection() method and passing an empty ArrayList. The toCollection() method then populates the ArrayList with all the values in the array.

Obviously, this isn’t ideal as we have to convert between the two types. It would be much nicer to be able to create and initialize an ArrayList directly. Fortunately, we can!

Initializing an ArrayList with arrayListOf

As it turns out, the collections library includes a function for building an ArrayList in Kotlin directly:

val list = arrayListOf<Int>(7, -4, 3)

I’m not totally sure how this method works under the hood, but I imagine it works similar to our brute force solution:

fun <T> arrayListOf(vararg elements: T): ArrayList<T> {
    val list = ArrayList<T>()
    for (element in elements) {
        list.add(element)
    }
    return list
}

In any case, we have a concise solution for building up an ArrayList. That’s exciting!

Performance

Since I got into the habit of measuring performance in Python, I thought I could transition that idea over to Kotlin. Fortunately, there is a standard function which will do just that: measureNanoTime. We’ll be using that to test each of the code snippets above:

import kotlin.system.measureNanoTime

val bruteForceTime = measureNanoTime {
    val list = ArrayList<Int>()
    list.add(7)
    list.add(-4)
    list.add(3)
}

val conversionTime = measureNanoTime {
    val list = intArrayOf(7, -4, 3).toCollection(ArrayList())
}

val arrayListOfTime = measureNanoTime {
    val list = arrayListOf<Int>(7, -4, 3)
}

println("Brute Force: $bruteForceTime")
println("Conversion: $conversionTime")
println("ArrayListOf: $arrayListOfTime")

In my case, the brute force method was significantly faster than the other two methods, but I’m not sure how these functions scale with more input. Feel free to try and let me know. At any rate, here are the results:

Brute Force: 38700

Conversion: 14728800

ArrayListOf: 6319000

For this test, I ended up using measureNanoTime over measureTimeMillis because I kept getting a value of zero for the brute force method. Now, that makes sense!

For reference, I tested everything on Windows 10 using Android Studio to setup a scratch file called scratch.kts. Also, I used Kotlin 1.3.31.

A Little Recap

As always, here are all the solutions in one convenient place:

// Brute force
val list = ArrayList<Int>()
list.add(7)
list.add(-4)
list.add(3)

// Array conversion
val list = intArrayOf(7, -4, 3).toCollection(ArrayList())

// Direct method
val list = arrayListOf<Int>(7, -4, 3)

Since I’m just starting to play with Kotlin, this may seem like a pretty trivial tutorial. That said, I guarantee I’ll start digging into more interesting topics. For instance, I’m already excited to start mirroring some of the Python articles.

While you’re here, why not support The Renegade Coder by becoming a member. You’ll get access to all kinds of fun articles like:

Of course, you’re welcome to just hop on the newsletter and decide at a later date. Either way, I appreciate the support.

The post How to Initialize an ArrayList in Kotlin appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/code/how-to-initialize-an-arraylist-in-kotlin/feed/ 0 16590
It’s Okay to Test Private Methods https://therenegadecoder.com/code/its-okay-to-test-private-methods/ https://therenegadecoder.com/code/its-okay-to-test-private-methods/#respond Fri, 21 Jun 2019 14:00:16 +0000 https://therenegadecoder.com/?p=16496

Usually, I try not to write too many opinion pieces about code, but I felt like I should mention that it's okay to test private methods.

The post It’s Okay to Test Private Methods appeared first on The Renegade Coder.

]]>

Google the phrase “should I test private methods,” and you’ll get a whole host of opinions that boil down to “no.” Fortunately, I’m here to say it’s okay to test private methods.

Table of Contents

What’s the Big Deal?

At the moment, I’m training to teach a software course at my university, and I was working on a utility class in Java which had a ton of private helper methods. In my particular case, there wasn’t actually any exposed public methods beyond main, and I find it challenging to write tests that interact with input streams. As a result, I wanted to write some JUnit tests to prove the functionality of the private methods.

However, when I turned to Google, I found that most of the experts say not to test private methods:

Instead, they argue that we should test our public methods which call our private methods. In the following subsections, I’ll try to break down their argument.

Private Methods Are Implementation Details

A common argument against testing private methods is that private methods are implementation details:

A private method is an implementation detail that should be hidden to the users of the class. Testing private methods breaks encapsulation.

jop, 2008

In other words, how a solution is implemented is irrelevant from a testing point of view. Ultimately, we want to test our solution based on its expected behavior to the user.

Private Method Tests Are Brittle

Since private methods are implementation details, we’re free to change those details with little or no cost to us. However, if we choose to test our private methods, we run the risk of breaking our tests. As a result, our tests become brittle meaning they break easily. In fact, I think a Stack Overflow user said it best:

The problem here is that those “future code changes” invariably mean refactoring the inner workings of some class. This happens so often that writing tests creates a barrier to refactoring.

Outlaw Programmer, 2008

In other words, brittle tests can hinder refactoring which provides a barrier to code improvement.

Private Method Test Failures May Not Matter

One of the more interesting arguments I’ve seen goes something like the following:

If you can’t break the public method does it really matter what the private methods are doing?

Rig, 2012

In other words, we may be able to break our private methods, but the exposed methods might be under different constraints that cause the error in the private method to never manifest.

A Case for Testing Private Methods

In general, I agree with all the arguments against testing private methods. In fact, if I hadn’t run into my own needs for testing private methods, I might have been on that side of the fence. As always, however, the issue is a bit more nuanced.

Public Methods Depend on Implementation Details

When we make the argument that we shouldn’t care about implementation details, we run the risk of missing edge cases where our public methods break down. In other words, knowing how our system is designed under the hood is critical to ensuring that it works correctly. How would we prove it works otherwise?

As a sort of silly example, imagine a Fibonacci sequence method which outputs the term in the sequence based on some index. If we test this method, how do we know how many inputs to try to verify that the method works? With black box testing, we’d have to try them all. With white box testing (which depends on implementation details), we’d just have to hit all the branches.

Of course, I don’t think anyone is making the argument that public methods shouldn’t be white box tested, but that does move me into my second point: public method tests are just as brittle as private method tests, and they’re often bloated.

Public Method Tests Are Brittle and Often Bloated

Since private method tests depend on implementation details, it’s possible that tests will break as requirements change. That said, I’m not sure public methods are in the clear in that regard either.

For instance, sometimes methods can affect the state of an object. We typically call these instance methods because they interact directly with an instance of an object. In order to test an instance method, we usually have to setup the state of that object so we can monitor its behavior when we call that method on it.

Since we’re stuck using public methods to setup our object during testing, we can run into a scenario where tests depend on the behavior of multiple methods—not necessarily the method under test. If we had access to private methods (setters for example), we would be able to set the state of the object without becoming dependent on other public methods that may or may not work.

To make matters worse, white box testing becomes a nightmare. Suddenly, we have to feed all sorts of data into our public API under the hope that we can get proper code coverage. It would be much easier to test the private methods directly and throw those tests away when those private methods are no longer needed.

In terms of readability alone, imagine trying to name 50+ unique tests for a single method. After several rounds of refactoring, you wouldn’t even know which tests would be worth deleting. Private method tests keep the separation of responsibility clear.

Finally, imagine deprecating a public method held together by 50+ tests. Not only do all those tests go to waste, but the sunk cost fallacy basically guarantees that we will refuse to deprecate a public method due to the amount of testing behind it. The momentum of the accumulated test cases alone will stop us from making our code better.

Private Method Test Failures Matter

Ultimately, we come to the final argument: if the public methods work, who cares what the private methods are doing? In other words, as long as the API works, who cares whether or not some internal feature fails some test. At least, I feel like that’s argument being made here, right?

To me, private method test failures should matter because that error may just manifest itself down the line. After all, coding is a dynamic process. In other words, an underlying issue may not manifest itself today, but it just may 3 versions down the line. As a result, actively ignoring a private method that may have a bug is a ticking time bomb.

In addition, I’m also not a fan of the sentiment made by this argument. To be honest, I’d be really worried if the same kind of argument were made in other engineering disciplines. For instance, I would hope that airplane manufacturers would thoroughly test their equipment even if they had triple redundancy to cover for failures.

That said, I do find the original argument to be the most compelling. We can debate the merit of testing private methods all day, but a lot of software just isn’t mission critical. In today’s world, software moves quickly, and public method testing is probably enough. Hell, I’d prefer that over telemetry.

It’s Okay to Test Private Methods

When I set out to write this piece, it was in response to the overwhelming amount of literature online that states that testing private methods is a bad idea. To be honest, I thought that was a little odd. After all, I’ve been in situations where a public method is built on layers of private methods, so testing the public interface becomes a really inefficient way of isolating bugs. In other words, how do we know how to write just the right test to exercise all the branches on some underlying private method?

At any rate, whether or not it’s actually practical to test private methods is a completely different question, but I wouldn’t go as far as to say that private method testing is good or bad. Like many debates in Computer Science, the issue is more nuanced.

Of course, in the process of writing this article, I was also working on an app in Kotlin, and I found it was much more practical to only test the public API. After all, the underlying private methods were all very small and easy to reason about. However, I can’t say the same for every project I’ve written, so I pass the choice off to you: do what makes sense and nothing more.

Right now, it makes sense to become a premium member of The Renegade Coder! With a premium membership, you’ll get full access to the blog, so you can get to know me a little better. If you need more time to figure things out, check out some of the following articles:

While you’re here, why not share how you feel about private method testing? Do you strictly avoid it, or are their situations where you think it makes sense?

The post It’s Okay to Test Private Methods appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/code/its-okay-to-test-private-methods/feed/ 0 16496
Taking Kotlin for a Spin https://therenegadecoder.com/code/taking-kotlin-for-a-spin/ https://therenegadecoder.com/code/taking-kotlin-for-a-spin/#respond Mon, 17 Jun 2019 14:00:01 +0000 https://therenegadecoder.com/?p=16528

After long last, I've finally decided to take a look at Kotlin while building an Android app. Now, I want to talk about the language.

The post Taking Kotlin for a Spin appeared first on The Renegade Coder.

]]>

Recently, my wife picked up a Kindle Fire, and I figured it would be fun to write an app for it. In fact, you may recall that I’ve been trying to make a library app for her for a long time. Well, what a better way to give it another chance than by taking Kotlin for a spin.

Table of Contents

Mobile App Development

My relationship with mobile app development has been rather brief. In fact, my one and only experience with it was my last semester of undergrad in 2016 when I built an Android app to interact with a smart lock.

At the time, I was only familiar with Java, C, Verilog, and x86. For the record, that was the expected repetoire for someone pursuing a Computer Engineering degree. Regardless, I hadn’t had much experience with anything beyond those languages, so I went the Android route to leverage my Java experience.

For those who are curious, we used an Arduino to drive a solenoid lock. The Arduino had a Bluetooth attachment which we used to communicate with the lock through an Android mobile app. To be honest, the project was pretty basic, but I had a lot of fun designing something from the ground up with in a multidisciplinary team.

Fast forward to today, and you’ll find that not much has change—at least not until recently. As a polyglot, I decided to not only take another stab at mobile app development but to also try my hand at Kotlin.

Revisiting PopLibrary

Back in early 2016, I decided to make a library application, PopLibrary, for my girlfriend-at-the-time, Morgan. She wanted something she could use to basically catalog her collection of books, so she could loan them to her students just like a library.

The Path to Failure

To make things interesting, I decided to expand the tool, so I could potentially make some money off it. In particular, I wanted to provide all the same functionality that Morgan wanted with the addition of features like book recommendations. Those recommendations would then tie into my Amazon Associates account which would earn me the big bucks—or at least so I thought.

Turns out, over the span of two years, I was unable to bring that application to life. I guess I just didn’t have the skills to be able to write a full stack application, and that reality never really set in. After all, I tried implementing PopLibrary three separate times:

  • Windows app in C#
  • JavaFX app
  • Laravel web app

After three attempts, I gave up. Then, Morgan bought a Kindle Fire, and I got all excited again. For whatever reason, I felt like things might be different.

Shifting Requirements

After failing three times, I decided this time around that I’d implement all the functionality that Morgan wants first. Then, I’ll try to see if I can make a little money on the side. With that said, PopLibrary should be able to do the following things:

  • Display a list of books that the user owns
  • Allow user to add and edit their own books (title, image, etc.)
  • Persist book data locally (long term goal: cloud storage)
  • Offer search and filter features to change which books display
  • Allow user to loan books to other users
  • Use the camera to scan bar codes

At this point, I already have the first few features implemented, and I’ve only been working on the app for about two days. It pays to have experience!

Kotlin Impressions

All that said, I’m sure you’re not here to learn about my project. You’re probably here for any number of reasons like:

  • Finding out whether or not it’s worth checking out Kotlin
  • Seeing what a first-timer thinks of the language
  • Sharing in some of the growing pains

Whatever the reason is, here’s my take on Kotlin so far.

Save Yourself from Null

Almost every language I’ve had the pleasure of playing with (C, C#, Java, Python, JavaScript, PHP, etc.) has had this notion of null. To me, null just made sense. After all, it’s the perfect value to give to a reference type when it’s value doesn’t exist. For example, if you provide a form to a user, and they choose not to fill out some of the optional elements, the values of those elements under the hood should be null—not some arbitrary value.

Well, at least, that was my understanding of null. I didn’t realize that it could be such an issue. In fact, there’s been a ton of literature regarding null as one of the biggest mistakes in computer science. Oddly enough, I hadn’t heard about this animosity toward null until I was writing my Hello World in Swift article in 2017.

Introducing Nullable

Due to the problems that null can introduce, a lot of modern languages have tried to remove them. At the very least, languages like Kotlin and Swift have wrapped null in objects which introduces some safety checking. In other words, no more NullPointerExceptions (NPEs) unless you’re asking for them.

In Kotlin in particular, you can set any variable to nullable using a question mark:

var count: Int? = null

Here, we’ve created a variable called count of type Int? meaning count could be a number or null. When using count, you might want to call a method on it like the decrement method:

count.dec()

Ideally, this method would decrement count, but count isn’t actually a number—it’s null. In most languages, we’d get an NPE, but Kotlin will actually fail to compile. To accomodate for this, we have to change the syntax slightly:

 count?.dec()

Here, we’ve performed a safe call on count. If count is null, the entire chain will return null, but we won’t get an NPE.

Nullable in Practice

Now, this is an awesome feature for null haters, but I’ve found that it can occasionally make life more difficult. For example, I created a Book class that looks something like the following:

data class Book(
    val isbn13: String? = null,
    val title: String? = null,
    val author: String? = null,
    val editor: String? = null,
    val language: String? = null,
    val coverImageURL: String? = null,
    val pageCount: Int? = null,
    val dateOfPublication: Date? = null
) { }

I’ve set every field to nullable because I don’t want to populate these fields with arbitrary data. In other words, I don’t want to setup the String fields as empty strings or some other arbitrary data because I’d have to remember what that default value was for checking later. Instead, I leave all unfilled fields as null and deal with the null issues as they come.

That said, I have run into a couple issues. For example, if I want to check if a string is contained in the title, I might write something like this:

title?.contains("Gatsby", true)

Of course, the problem here is that this expression could return true, false, or null. In a language like JavaScript, conditions might be able to deal with that kind of ambiguity but not in Kotlin. As a result, we basically have to force the null value to false using the Elvis operator:

title?.contains("Gatsby", true) ?: false

In other words, if title is null then the expression returns false.

Now, imagine having some sort of condition that check a few of these terms. Very quickly, we end up with a messy expression which requires the Elvis operator to handle any sort of null possibilities. I ended up wrapping the expression above in a function and chained the different possibilities together using the OR operator:

checkContains(title, str)
    || checkContains(author, str)
    || checkContains(editor, str)
    || checkContains(language, str)

Obviously, this isn’t ideal, but there are no NPEs! I imagine more seasoned Kotlin developers would have a better way of dealing with this problem, but I’m just trying to get an app running.

Compare Objects with Operator Overloading

While Kotlin’s most interesting feature to me is null safety, I have to say that operator overloading is a close second. Normally, I would be totally against operator overloading as it introduces unnecessary complexity to a language, but I think Kotlin does a pretty nice job with the feature.

Unfortunately, for you to get an appreciation for the feature, you need to know a little bit about how Java works. In particular, you need to be familiar with the equals() method of objects and the compareTo() method of the comparable interface.

Object Equivalence

In Java, all objects have an equals() method, so they can be tested against another object for equality. Of course, the alternative to equals() is the == operator, but it serves a different purpose. Instead of testing whether or not two objects are equivalent, the == operator tests whether or not two objects have the same identity. In other words, if two objects have the same identity, they’re actually one object with multiple aliases.

In Kotlin, the == is used universally for equality. Meanwhile, identity checking is handled with the === operator. As a result, == and equals() are synonymous. Once we’ve implemented the equals() method, we can use the == operator in its place:

val x = Date(1000)
val y = Date(1000)
x.equals(y) // Evaluates equality based on equals() implementation 
x == y // Does the same exact thing

As it turns, IntelliJ actually promotes using the operator over the method, and I’m a huge fan. But wait, it gets better!

Object Comparison

In Java, when we want to compare two objects—say, for sorting purposes—we usually make sure to implement the Comparable interface. As a part of that interface, we have to override the compareTo() method which takes a pair of objects and returns a number that represents their relationship. When the two objects are equivalent, the method should return 0. Meanwhile, the method should return a positive number when the calling object is the “bigger” object and a negative number otherwise.

Determining which object is “bigger” depends on the type of object we’re using. For example, the string “apple” is smaller than the string “carrot” because alphabetical ordering dictates that “apple” comes first. In other words, compareTo should behave as follows:

"apple".compareTo("carrot") // Returns some negative number
"carrot".compareTo("apple") // Returns some positive number

At any rate, compareTo is sort of confusing, and Kotlin does a nice job of alleviating some of that confusion by introducing a few operators. Using the same example as above, we can compare “apple” and “carrot” using the relational operators:

"apple" > "carrot" // false
"apple" < "carrot" // true

Personally, I used this for sorting books by their Lexile level. In my project, Lexile is a class which implements Comparable. To compare them, I use their numeric value:

override fun compareTo(other: Lexile): Int {
    return this.toInteger() - other.toInteger()
}

Then, I can compare two Lexile objects as follows:

val lex1 = Lexile(270, Lexile.LexileType.NA)
val lex2 = Lexile(400, Lexile.LexileType.NA)
assertTrue(lex1 < lex2)

Now, I think that’s pretty cool.

Say Goodbye to Verbosity

One of the biggest complaints people have about Java is the language’s verbosity. In particular, variable definitions require an overwhelming amount of detail:

ArrayList<Integer> myList = new ArrayList<Integer>()

In order to create this list, we had to specify a lot of information:

  • Type, twice
  • Generic type, twice
  • Name
  • Keyword (new)
  • Operator (=)
  • Constructor

Naturally, this line of code can grow exponentially in length depending on factors like the length of the type’s name, the number of nested generic types, and the size of the constructor.

To deal with this, Kotlin introduces a much more concise syntax:

val list = arrayListOf<Int>()

Obviously, there’s a lot going on here, but it’s important to take note of the lack of redundant information. We don’t specify the type, but we have the option. Also, populating the ArrayList is significantly easier:

val list = arrayListOf<Int>(5, 6, 8, -4)

Now while the reduced verbosity is nice, I would also like to point out that Kotlin has introduced two new keywords as well: val and var. We use val when we want to mark a variable as immutable or read-only (think final from Java) and var to mark a variable as mutable.

Mastering the Art of Flow Control

If there’s anything I’ve learned from playing around with programming languages, there are a ton of flow control mechanisms. For instance, there are if statements and loops just for starters. Then, there are fun mechanisms like goto and switch statements which offer even more options for flow control.

All that said, Kotlin introduced yet another flow control mechanism to me: when. It’s essentially a switch statement, but I find the syntax to be a lot cleaner:

override fun toString(): String {
    return when (this.type) {
        LexileType.NA -> level.toString() + "L"
        else -> type.name + level.toString() + "L"
    }
}

In this method, we’ve overridden the toString() method to return a string under two possible conditions:

  • The type is NA
  • The type is anything else

In particular, we return the result of a when statement which accepts this object’s type (same Lexile class from earlier). If the type is NA, we return some string. Otherwise, we return some other string.

In my opinion, the when statement is clever because it removes a lot of redundant code that you might find in a switch statement: break, return, etc. Naturally, I’ve been using them quite a bit because IntelliJ actually prefers them over chains of if statements. Also, I just think they’re cool.

The Verdict

As of right now, I like Kotlin a lot. The null safety feature has been tough to work around, but everything else is great. Kotlin is everything I love about Java plus everything I love about higher level languages like Python. With most of the boilerplate out of the way, I feel like I can really build something quickly while also relying on all the amazing static analysis utilities that come standard with compiled languages.

All that said, we’ll see how I’m feeling soon. I’m probably just in the honeymoon phase, but I’m really enjoying this language. It sort of reminds me of how I felt when I first started using C#—both are big improvements over Java.

Since this is my first time really reviewing a language in depth like this, I don’t really have any articles to recommend. Regardless, here are a couple articles I’d love to get in front of more eyes:

Also, if you enjoyed this article, give it a share! By the time it publishes, I will probably have a totally different opinion on the subject, so let’s also have a dialogue. For those of you that want to foster some community, make your way over to the members page and sign up! For the less committed, there’s also a newsletter. As always, thanks for stopping by!

The post Taking Kotlin for a Spin appeared first on The Renegade Coder.

]]>
https://therenegadecoder.com/code/taking-kotlin-for-a-spin/feed/ 0 16528