# Stories by Roman Elizarov on Medium

Stories by Roman Elizarov on Medium

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## Programming Language Evolution

DevFeed: [Programming Language Evolution](<https://devfeed.tech/articles/programming-language-evolution-26026.md>)

Original publisher: [Read original article](<https://elizarov.medium.com/programming-language-evolution-ab7d7d2b0d0b?source=rss-4762e889f8fc------2>)

Author: Roman Elizarov

Published: 2020-11-23T16:18:08Z

Content type: opinion

Language: en

Sources: [Stories by Roman Elizarov on Medium](<https://devfeed.tech/sources/stories-by-roman-elizarov-on-medium.md>)

Topics: [Programming](<https://devfeed.tech/topics/programming.md>), [Programming language](<https://devfeed.tech/topics/programming-language.md>), [Code](<https://devfeed.tech/topics/code.md>), [Object-oriented programming (OOP)](<https://devfeed.tech/topics/oop.md>), [C](<https://devfeed.tech/topics/c.md>), [Java](<https://devfeed.tech/topics/java.md>), [Python](<https://devfeed.tech/topics/python.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [evolution](<https://devfeed.tech/tags/evolution.md>), [history](<https://devfeed.tech/tags/history.md>), [improvements](<https://devfeed.tech/tags/improvements.md>), [language](<https://devfeed.tech/tags/language.md>), [loops](<https://devfeed.tech/tags/loops.md>), [oop](<https://devfeed.tech/tags/oop.md>), [patterns](<https://devfeed.tech/tags/patterns.md>), [pointers](<https://devfeed.tech/tags/pointers.md>), [programming](<https://devfeed.tech/tags/programming.md>), [programming-language](<https://devfeed.tech/tags/programming-language.md>), [programming-languages](<https://devfeed.tech/tags/programming-languages.md>), [software](<https://devfeed.tech/tags/software.md>)

### AI overview

The article examines how programming languages evolve through gradual improvements that follow changes in programming practice. It uses the transition from GOTOs to structured loops and the adoption of object-oriented patterns, classes, methods, and implicit object references as examples.

### Source excerpt

Photo by Anne Nygård on Unsplash The history of programming languages is ripe with evolution. Existing languages constantly evolve and new languages are created to address the emerging needs. Sometimes there are radical, revolutionary breakthroughs, with a complete paradigm shift, but often there are just gradual improvements and refinements. The latter is the topic of this story. The practice of programming at any given era usually goes ahead of capabilities that programming languages provide, while programming language designers recognize it and catch up to fulfill the demand. Let us see some examples to the point. From GOTOs to the structured code In early languages, you had to write a lot of repetitive code just to do a simple loop. The loop was such a common programming pattern, that it was adopted even by the primitive higher-level languages in the era predating structured programming. So, there was a time when you still had GOTOs in your programming language but a significant fraction of the code had structured loops: 10 LET N=10 20 FOR I=1 TO N 30 PRINT "Hello, World!" 40 NEXT I As we know, the subsequent generation of languages not only added structured IF statements but also made the structure explicit in the source and ended up abolishing GOTOs completely. This kind of evolution can be seen in other areas, too. Objects and pointers Let's take a brief look at OOP. The object-oriented style of programming does not need an object-oriented language. Even nowadays you can find software written in C where methods are just a convention of writing functions whose first parameter is a pointer to the receiver: void Point_move(Point* self, int dx, int dy) { ... } Virtual methods are routinely implemented in pure C, too, explicitly keeping a virtual methods table with references to methods somewhere in the object's structure. However, the rising popularity of object-oriented programming back in the day cemented the growth of languages that incorporated these patterns

## Shared flows, broadcast channels

DevFeed: [Shared flows, broadcast channels](<https://devfeed.tech/articles/shared-flows-broadcast-channels-26027.md>)

Original publisher: [Read original article](<https://elizarov.medium.com/shared-flows-broadcast-channels-899b675e805c?source=rss-4762e889f8fc------2>)

Author: Roman Elizarov

Published: 2020-11-16T13:16:59Z

Content type: article

Language: en

Sources: [Stories by Roman Elizarov on Medium](<https://devfeed.tech/sources/stories-by-roman-elizarov-on-medium.md>)

Topics: [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [kotlin-flow](<https://devfeed.tech/topics/kotlin-flow.md>), [Coroutines](<https://devfeed.tech/topics/coroutines.md>), [Concurrent Programming](<https://devfeed.tech/topics/concurrent-programming.md>), [Streams](<https://devfeed.tech/topics/streams.md>)

Tags: [asynchronous](<https://devfeed.tech/tags/asynchronous.md>), [channel](<https://devfeed.tech/tags/channel.md>), [concurrent](<https://devfeed.tech/tags/concurrent.md>), [coroutine](<https://devfeed.tech/tags/coroutine.md>), [flow](<https://devfeed.tech/tags/flow.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-flow](<https://devfeed.tech/tags/kotlin-flow.md>), [streams](<https://devfeed.tech/tags/streams.md>), [synchronization](<https://devfeed.tech/tags/synchronization.md>)

### AI overview

This article explains why Kotlin shared flows were introduced as a replacement for broadcast channels for distributing events and state updates to multiple subscribers. It contrasts channel-based transformations with Kotlin Flow, emphasizing the synchronization costs of channels and the efficiency of flow transformations.

### Source excerpt

Photo by Davies Designs Studio on Unsplash Once upon a time coroutines were introduced to Kotlin and they were lightweight. We could launch a multitude of coroutines and we needed a way to communicate between those coroutines without running into a dreaded "mutable shared state" problem. Thus Channel was added as an inter-coroutine communication primitive. The channels are wonderful. Channels support one-to-one, one-to-many, many-to-one, and many-to-many communication between coroutines, and every value that is sent to the channel is received once. Diagram of many-to-many channel operation You cannot use channels to distribute events or state updates in a way that allows multiple subscribers to independently receive and react upon them. Thus the BroadcastChannel interface was introduced with buffered and ConflatedBroadcastChannel as its implementations. They served us well for a while, but they turned out to be a design dead-end. Now, since kotlinx-coroutines version 1.4 we have introduced a better solution -- shared flows. Read on for the full story. Flows are simple In the early versions of the library, we had only channels and we tried to implement various transformations of asynchronous sequences as functions that take one channel as an argument and return another channel as a result. It means that, for example, a filter operator would run in its own coroutine. Diagram of filter operator with channels The performance of such an operator was far from great, especially compared to just writing an if statement. In a hindsight, it is not surprising, because a channel is a synchronization primitive. Any channel, even an implementation that is optimized for a single producer and a single consumer, must support concurrent communicating coroutines and a data transfer between them needs synchronization, which is expensive in modern multicore systems. When you start building your application architecture on top of the asynchronous data streams, the need to have transformat

## Immutability we can afford

DevFeed: [Immutability we can afford](<https://devfeed.tech/articles/immutability-we-can-afford-26022.md>)

Original publisher: [Read original article](<https://elizarov.medium.com/immutability-we-can-afford-10c0dcb8351d?source=rss-4762e889f8fc------2>)

Author: Roman Elizarov

Published: 2020-07-22T09:18:28Z

Content type: opinion

Language: en

Sources: [Stories by Roman Elizarov on Medium](<https://devfeed.tech/sources/stories-by-roman-elizarov-on-medium.md>)

Topics: [Software Engineering](<https://devfeed.tech/topics/software-engineering.md>), [Programming](<https://devfeed.tech/topics/programming.md>), [Software](<https://devfeed.tech/topics/software.md>), [ui](<https://devfeed.tech/topics/ui.md>), [Caching](<https://devfeed.tech/topics/caching.md>)

Tags: [architecture](<https://devfeed.tech/tags/architecture.md>), [asynchronous](<https://devfeed.tech/tags/asynchronous.md>), [caching](<https://devfeed.tech/tags/caching.md>), [code](<https://devfeed.tech/tags/code.md>), [debugging](<https://devfeed.tech/tags/debugging.md>), [immutability](<https://devfeed.tech/tags/immutability.md>), [languages](<https://devfeed.tech/tags/languages.md>), [object](<https://devfeed.tech/tags/object.md>), [programming](<https://devfeed.tech/tags/programming.md>), [programming-languages](<https://devfeed.tech/tags/programming-languages.md>), [software-engineering](<https://devfeed.tech/tags/software-engineering.md>), [state](<https://devfeed.tech/tags/state.md>), [ui](<https://devfeed.tech/tags/ui.md>)

### AI overview

The article traces the shift from mutable global state and object-encapsulated state toward immutability. It argues that mutable state becomes difficult to reason about in user interfaces and asynchronous systems, where unexpected mutations complicate debugging, event processing, and caching.

### Source excerpt

Photo by Li Yang on Unsplash At the dawn of software engineering computers were programmed directly in machine code, then in assembly, and only later in higher-level languages. Computers are imperative. They operate by executing instructions that mutate their state, stored in registers and memory. Naturally, the same was true about programming languages. In the old world of expensive computers with limited resources, the primary concern was an efficient translation of higher-level abstractions into low-level code. The past glory of mutable state It used to be a normal practice to write software in a way that mimics the actual computer architecture with thousands of global variables that are being mutated by various pieces of the system. It might be shocking for a modern developer to learn that just recently there were cars on the street, designed as late as 2005, that ran what we would call the "Spaghetti" code. The software industry, in general, had firmly moved past the unruly global state before the end of the last century. The rise of the object-oriented programming paradigm had established an orderly approach with the encapsulation of all the mutable state in our software systems inside of objects. It had fueled tremendous growth in the complexity of modern software, layering abstractions above abstractions, while still maintaining a reasonable degree of human's ability to make sense of it. However, any developer who worked on a non-trivial piece of UI using an object-oriented framework, or had programmed in another domain with lots of asynchronously occurring events, can tell you stories of debugging all those cases where mutable state, even encapsulated into objects, continually trips you. You expect this object to be in a such and such state, but due to some rare sequence of events, it turns out to be in a state you did not expect, having been mutated by another piece of code. For example, take a popular architectural pattern where a repository class encapsu

## Using Kotlin's with Scope Function and Receiver Lambdas

DevFeed: [Using Kotlin's with Scope Function and Receiver Lambdas](<https://devfeed.tech/articles/with-the-receiver-in-scope-26030.md>)

Original publisher: [Read original article](<https://elizarov.medium.com/with-the-receiver-in-scope-7b52bdcca6e9?source=rss-4762e889f8fc------2>)

Author: Roman Elizarov

Published: 2020-07-01T14:33:13Z

Content type: tutorial

Language: en

Sources: [Stories by Roman Elizarov on Medium](<https://devfeed.tech/sources/stories-by-roman-elizarov-on-medium.md>)

Topics: [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Programming language](<https://devfeed.tech/topics/programming-language.md>), [Library](<https://devfeed.tech/topics/library.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [context](<https://devfeed.tech/tags/context.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [lambda](<https://devfeed.tech/tags/lambda.md>), [programming](<https://devfeed.tech/tags/programming.md>), [programming-language](<https://devfeed.tech/tags/programming-language.md>), [receiver](<https://devfeed.tech/tags/receiver.md>), [scope-function](<https://devfeed.tech/tags/scope-function.md>), [scopes](<https://devfeed.tech/tags/scopes.md>), [standard-library](<https://devfeed.tech/tags/standard-library.md>)

### AI overview

The article explains how Kotlin's with scope function reduces repetitive object references and groups related initialization in a distinct block. It also introduces extension functions and lambdas with a receiver as ways to access object members without repeating the object's name.

### Source excerpt

Photo by Ben Wicks on UnsplashRepetitio est mater studiorum (Latin, repetition is the mother of all learning). Repetition is great for study, but a bane of software development. Repetitive code is boring and error-prone. Let's look at a hypothetical example inspired by imperative UI frameworks that are still being used a lot nowadays, even though their heyday is past. We might find ourselves having to write code like this: applicationWindow.title = "Just an example" applicationWindow.position = FramePosition.AUTO applicationWindow.content = createContent() applicationWindow.show() Referencing applicationWindow object over and over again is very explicit but it is not pretty. We can make this code better using with scope function from the Kotlin standard library: with(applicationWindow) { // this: ApplicationWindow title = "Just an example" position = FramePosition.AUTO content = createContent() show() } This code now has more lines, but the number of lines is not the key metric you should be looking at when judging the code. The code looks cleaner. It groups all the initialization of the applicationWindow object into a separate, syntactically distinct block. It directly represents the developer's intent to perform all of these actions on applicationWindow together. The block of code inside of with(x) { ... } is easily recognizable by any developer trained in a mainstream object-oriented language -- it is similar to the code you encounter inside a method of the corresponding class where this refers to the method's receiver object and all unqualified references like title refer to this object's properties and methods. In the Kotlin programming language writing a method is not the only way to get access to object members without having to repeat the object's name. Kotlin has support for extension functions that allow us to write a method-like looking code outside of the class body: fun ApplicationWindow.configure() { // this: ApplicationWindow title = ... // no need to

## Kotlin and Exceptions

DevFeed: [Kotlin and Exceptions](<https://devfeed.tech/articles/kotlin-and-exceptions-26024.md>)

Original publisher: [Read original article](<https://elizarov.medium.com/kotlin-and-exceptions-8062f589d07?source=rss-4762e889f8fc------2>)

Author: Roman Elizarov

Published: 2020-06-10T08:18:06Z

Content type: article

Language: en

Sources: [Stories by Roman Elizarov on Medium](<https://devfeed.tech/sources/stories-by-roman-elizarov-on-medium.md>)

Topics: [Exception](<https://devfeed.tech/topics/exception.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Java](<https://devfeed.tech/topics/java.md>), [Error Handling](<https://devfeed.tech/topics/error-handling.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [api-design](<https://devfeed.tech/tags/api-design.md>), [code](<https://devfeed.tech/tags/code.md>), [error-handling](<https://devfeed.tech/tags/error-handling.md>), [exception-handling](<https://devfeed.tech/tags/exception-handling.md>), [exceptions](<https://devfeed.tech/tags/exceptions.md>), [java](<https://devfeed.tech/tags/java.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [programming](<https://devfeed.tech/tags/programming.md>)

### AI overview

The article examines Kotlin exceptions by tracing their origins to Java checked exceptions. It explains how checked exceptions were intended to reduce missed error checks, then discusses problems including boilerplate, overly broad API declarations, ignored exceptions, and poor compatibility with Java 8 lambdas and streams.

### Source excerpt

Photo by John Mark Arnold on Unsplash What are Kotlin Exceptions and how should you use them? To figure it out let's look at their origins first. Exceptions came to Kotlin from Java. The story with exceptions in Java is complicated, though. I'll give a brief overview. The Origin Java has a unique concept of checked exceptions that were designed to solve the problem of verbose and error-prone error-handling (pun intended). In languages predating Java, like in venerable C, you have to write code like shown in this snippet when doing basic input/output: file = fopen("file.txt", "r"); if (file == NULL) { // handle error & return } // work with file, check for error after each file operation Every time you perform an operation that might fail due to some external circumstance, which happens especially often with files and network, you have to write code that checks the corresponding error condition and handles it. That's tedious, easy to forget, hard to debug. Java set on a noble goal to eliminate this problem. The solution was to use checked exceptions. Every file I/O operation is declared as throws IOException in Java and the compiler checks that you either handle it or declare that you rethrow it. The beauty of this is that you can write exception-handling code once for a whole bunch of I/O operations and you cannot forget writing it since the Java compiler is there to help you. file = FileInputStream("file.txt"); // throws IOException No error-handling boilerplate, no more missed error checks. It was such a bliss to program in Java... for a while. Problems Problems with checked exceptions accumulated over the years. Memory input/output APIs like ByteArrayInputStream were still declared to throw IOException that you had to handle even though it never happened, people abused checked exceptions in API design leading to long, contagious lists of thrown exceptions, developers routinely caught and ignored checked exceptions just to fit some exception-throwing API under an in

## Phantom of the Coroutine

DevFeed: [Phantom of the Coroutine](<https://devfeed.tech/articles/phantom-of-the-coroutine-26025.md>)

Original publisher: [Read original article](<https://elizarov.medium.com/phantom-of-the-coroutine-afc63b03a131?source=rss-4762e889f8fc------2>)

Author: Roman Elizarov

Published: 2020-05-10T07:53:50Z

Content type: tutorial

Language: en

Sources: [Stories by Roman Elizarov on Medium](<https://devfeed.tech/sources/stories-by-roman-elizarov-on-medium.md>)

Topics: [Coroutines](<https://devfeed.tech/topics/coroutines.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Programming](<https://devfeed.tech/topics/programming.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [concurrency](<https://devfeed.tech/tags/concurrency.md>), [coroutine](<https://devfeed.tech/tags/coroutine.md>), [coroutines](<https://devfeed.tech/tags/coroutines.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-coroutines](<https://devfeed.tech/tags/kotlin-coroutines.md>), [programming](<https://devfeed.tech/tags/programming.md>)

### AI overview

The article explains why coroutines are ephemeral rather than manipulable objects like threads. It introduces coroutine transparency, showing how concurrency can be added with coroutineScope and launch while remaining largely invisible to callers, and discusses immutable coroutine context as a consequence.

### Source excerpt

Photo by Linus Mimietz on Unsplash Threads are heavy-weight and have substance. With threads, we can get a reference to some kind of current Thread object, examine its properties, modify its thread-local variables, and otherwise manipulate it. It is no surprise that people with the thread-programming background and education, who are coming to programming with coroutines, are looking for some kind of Coroutine object they can get hold of. However, there is none. Coroutines are phantom, ephemeral, insubstantial. There are good reasons for this state of affairs and some non-trivial consequences. Let's dig in. The rule of coroutine transparency Consider the following suspending function foo that performs some work and then writes the resulting data to a database and sends a message with it over a message bus (both use network and are suspending, too). suspend fun foo() { val data = doSomeWork() writeToDatabase(data) sendMessage(data) } We can speed foo function up by calling writeToDatabase concurrently with the rest of the code that does sendMessage. It is straightforward-- just delimit a scope for this concurrent operation and use launch function: suspend fun foo() = coroutineScope { val data = doSomeWork() launch { writeToDatabase(data) } // concurrent now sendMessage(data) }We don't have to explicity wait for writeToDatabase operation to complete before returning from foo because coroutineScope builder does this wait automatically. The rule of coroutine transparency states that neither the caller of foo nor the function writeToDatabase should be aware of or be affected by this introduction of concurrency. Having a separate coroutine should be completely transparent. Stated more narrowly, replacing a direct call to writeToDatabase(data) with a call from another coroutine viacoroutineScope { launch { writeToDatabase(data) } } should have as little noticeable effects as possible. Of course, all software abstractions are leaky and we only have an illusion of true transp

## Deep recursion with coroutines

DevFeed: [Deep recursion with coroutines](<https://devfeed.tech/articles/deep-recursion-with-coroutines-26021.md>)

Original publisher: [Read original article](<https://elizarov.medium.com/deep-recursion-with-coroutines-7c53e15993e3?source=rss-4762e889f8fc------2>)

Author: Roman Elizarov

Published: 2020-04-25T20:33:55Z

Content type: tutorial

Language: en

Sources: [Stories by Roman Elizarov on Medium](<https://devfeed.tech/sources/stories-by-roman-elizarov-on-medium.md>)

Topics: [Coroutines](<https://devfeed.tech/topics/coroutines.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Data structures](<https://devfeed.tech/topics/data-structures.md>), [Programming](<https://devfeed.tech/topics/programming.md>)

Tags: [coroutine](<https://devfeed.tech/tags/coroutine.md>), [coroutines](<https://devfeed.tech/tags/coroutines.md>), [data-structures](<https://devfeed.tech/tags/data-structures.md>), [exception](<https://devfeed.tech/tags/exception.md>), [jvm](<https://devfeed.tech/tags/jvm.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-coroutines](<https://devfeed.tech/tags/kotlin-coroutines.md>), [recursion](<https://devfeed.tech/tags/recursion.md>)

### AI overview

This tutorial explains how Kotlin coroutines can be used to handle deeply recursive functions. Using a 100,000-node binary tree as an example, it shows that ordinary recursion can exhaust the thread call stack and lead to a StackOverflowError, then introduces rewriting the algorithm to use heap memory instead.

### Source excerpt

Photo by Riccardo Pelati on Unsplash Kotlin Coroutines are typically used for asynchronous programming. However, the underlying design of coroutines and their implementation in Kotlin compiler are quite universal, solving problems beyond asynchronous programming. Let's take a look at one such problem that can be elegantly solved with coroutines-- writing deeply recursive functions. Setup Consider a tree data structure. For this example, let's use this simple binary tree where each Tree node has a reference to its left and right children: class Tree(val left: Tree?, val right: Tree?) The depth of the tree is defined as the length of the longest path from its root to its child nodes. It can be computed by the following recursive function: fun depth(t: Tree?): Int = if (t == null) 0 else maxOf( depth(t.left), // recursive call one depth(t.right) // recursive call two ) + 1 The logic here is straightforward. The depth is simply the maximum of the depth of the left and right children plus one, with the special case of zero when the tree is empty. Recursion is a great tool for working with tree-like data structures, but there is a catch. Let's generate a deep tree containing 100K nodes. Start with a leaf node Tree(null, null) as a seed and repeatedly generate parent nodes that link to the previous node as their left children: val n = 100_000 val deepTree = generateSequence(Tree(null, null)) { prev -> Tree(prev, null) }.take(n).last() This is not a particularly big data structure. It occupies less than 2MiB of memory, which is not much at all for a modern machine with gigabytes of available memory. Now, let's try to use our depth function on it: https://medium.com/media/f919e36404c4bf79aef919395ab51918/href If you run it in Kotlin Playground you'll get "Your program produces too much output!" message. If you run the same code on your local machine you'll see what kind of output that is: Exception in thread "main" java.lang.StackOverflowError at FileKt.depth(File.kt:5) ... /

## The End of the Semicolon Era

DevFeed: [The End of the Semicolon Era](<https://devfeed.tech/articles/the-end-of-the-semicolon-era-26029.md>)

Original publisher: [Read original article](<https://elizarov.medium.com/the-end-of-the-semicolon-era-60ab95e669ab?source=rss-4762e889f8fc------2>)

Author: Roman Elizarov

Published: 2020-02-09T11:33:53Z

Content type: opinion

Language: en

Sources: [Stories by Roman Elizarov on Medium](<https://devfeed.tech/sources/stories-by-roman-elizarov-on-medium.md>)

Topics: [Programming](<https://devfeed.tech/topics/programming.md>), [Programming language](<https://devfeed.tech/topics/programming-language.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Python](<https://devfeed.tech/topics/python.md>), [Scala](<https://devfeed.tech/topics/scala.md>), [Go Language](<https://devfeed.tech/topics/go-language.md>), [Swift](<https://devfeed.tech/topics/swift.md>)

Tags: [go](<https://devfeed.tech/tags/go.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [language](<https://devfeed.tech/tags/language.md>), [programming](<https://devfeed.tech/tags/programming.md>), [programming-language](<https://devfeed.tech/tags/programming-language.md>), [python](<https://devfeed.tech/tags/python.md>), [scala](<https://devfeed.tech/tags/scala.md>), [swift](<https://devfeed.tech/tags/swift.md>)

### AI overview

The article reflects on the decline of mandatory semicolons in programming languages. It argues that Scala, Go, Kotlin, Swift, and the rising popularity of Python illustrate a broader preference for concise syntax, supported by type inference while retaining type safety and scalability.

### Source excerpt

DeadEnd by Austin Mulhern Throughout most of my early professional career, I programmed in languages where you terminate or separate statements with a semicolon; it was like an ideograph distinguishing coders from laypeople. I had a motor reflex to type a semicolon (;) without having to think about it. So when I got involved in the early discussions about the new language that JetBrains was working on back in 2010, the language that would be later called Kotlin, I was not thrilled about the proposal to drop the mandatory semicolons. Who minds the semicolons I thought. I had quite a strong opinion about the need to solve the billion-dollar problem with nulls¹ to make our software safer, but the visuals I cared less about. How narrowminded I was! As it turns out, the disappearance of the semicolon has become the distinguishing characteristic of the rising modern languages of the late 2000s and 2010s to such an extent that it almost becomes synonymous with the very feeling of programming in the "modern language". Scala (2004), Go (2009), Kotlin (2011), and Swift (2014) are all statically typed, all follow C/C++/Java syntactic tradition with curly braces, all were introduced and grew big in the last 20 years and all had totally ditched the mandatory semicolon despite the tradition. Is it a coincidence? I don't think so. I see a trend here. The ground zero Let's take a look at the elephant in the room -- Python programming language (1990). While it is not exactly "modern", it has enjoyed a meteoric rise in popularity only recently. It became the most popular programming language by some forward-looking metrics like PYPL² and is consistently placed into the top three. Syntactically Python is a thing in itself. It is a rare breed of fully indentation-sensitive language (aka off-side rule³) that is not some kind of an academic or a toy language. The clean and concise looks of Python code are quite appealing. Switching from something as lean as Python (unless you try object-o

## Intentional qualities

DevFeed: [Intentional qualities](<https://devfeed.tech/articles/intentional-qualities-26023.md>)

Original publisher: [Read original article](<https://elizarov.medium.com/intentional-qualities-7e6a57bb87fc?source=rss-4762e889f8fc------2>)

Author: Roman Elizarov

Published: 2019-10-19T14:36:35Z

Content type: opinion

Language: en

Sources: [Stories by Roman Elizarov on Medium](<https://devfeed.tech/sources/stories-by-roman-elizarov-on-medium.md>)

Topics: [Software](<https://devfeed.tech/topics/software.md>), [Requirements](<https://devfeed.tech/topics/requirements.md>), [Usability](<https://devfeed.tech/topics/usability.md>)

Tags: [comparison](<https://devfeed.tech/tags/comparison.md>), [programming](<https://devfeed.tech/tags/programming.md>), [quality](<https://devfeed.tech/tags/quality.md>), [requirements](<https://devfeed.tech/tags/requirements.md>), [security](<https://devfeed.tech/tags/security.md>), [software](<https://devfeed.tech/tags/software.md>), [software-development](<https://devfeed.tech/tags/software-development.md>), [speed](<https://devfeed.tech/tags/speed.md>), [usability](<https://devfeed.tech/tags/usability.md>)

### AI overview

This commentary explains why software quality attributes such as reliability, efficiency, security, maintainability, and usability require deliberate goals and ongoing attention. It argues that qualities cannot be acquired accidentally and are difficult to evaluate, especially when selecting libraries or comparing non-functional requirements.

### Source excerpt

Vernier Caliper by Michael Brace When we work on a piece of software, being it an application or a library, we often focus on its functional requirements. They are usually quite easy to directly observe and test; functional requirements are featured in software marketing materials in the form of "feature matrix" that compares different products. Yet, many non-functional aspects of software, also known as quality attributes or qualities for short, such as reliability, efficiency, security, maintainability, usability, etc¹ can be important, too. They are not as easy to measure, though. Consider, for a example, a task of picking a library to parse some data interchange format. When you face a problem like this, you might have in mind some specific requirements like "it should be able to parse this and that file we have". You can quickly sketch test code to vet the candidates you've found. It is even simpler if the format is formally defined in some standard or standard-like written document. You'll just read documentation to confirm that the library claims conformance with the corresponding standard and then all you need to do is to perform a straightforward acceptance test. Trust, but verify. But what happens if you want to find a fast parser, for example, or if you have some other quality attribute in mind that shall be satisfied to suit your needs? Measuring qualities is way more complicated and quite a non-trivial endeavor. Even simple things, like speed, being it either response time or bandwidth, need a proper test setup and a lot of skill. It is time consuming. In the past I used to spend a lot of time when faced with a problem like that. You are lucky if you can find a ready-to-use quality comparison in your domain, but more often than not, all kinds of comparisons for non-functional requirements that you can find on the internet are of a very low quality (pun intended). However, over time I've discovered a shortcut. See, the fact is that you cannot accidentall

## Structured Concurrency Anniversary

DevFeed: [Structured Concurrency Anniversary](<https://devfeed.tech/articles/structured-concurrency-anniversary-26028.md>)

Original publisher: [Read original article](<https://elizarov.medium.com/structured-concurrency-anniversary-f2cc748b2401?source=rss-4762e889f8fc------2>)

Author: Roman Elizarov

Published: 2019-09-28T15:02:02Z

Content type: article

Language: en

Sources: [Stories by Roman Elizarov on Medium](<https://devfeed.tech/sources/stories-by-roman-elizarov-on-medium.md>)

Topics: [Concurrency](<https://devfeed.tech/topics/concurrency.md>), [Kotlin](<https://devfeed.tech/topics/kotlin.md>), [Coroutines](<https://devfeed.tech/topics/coroutines.md>), [kotlin-coroutines](<https://devfeed.tech/topics/kotlin-coroutines.md>), [Android](<https://devfeed.tech/topics/android.md>), [reactive](<https://devfeed.tech/topics/reactive.md>), [Documentation](<https://devfeed.tech/topics/documentation.md>)

Tags: [android](<https://devfeed.tech/tags/android.md>), [asynchronous](<https://devfeed.tech/tags/asynchronous.md>), [code](<https://devfeed.tech/tags/code.md>), [concurrency](<https://devfeed.tech/tags/concurrency.md>), [coroutine](<https://devfeed.tech/tags/coroutine.md>), [coroutines](<https://devfeed.tech/tags/coroutines.md>), [documentation](<https://devfeed.tech/tags/documentation.md>), [kotlin](<https://devfeed.tech/tags/kotlin.md>), [kotlin-coroutines](<https://devfeed.tech/tags/kotlin-coroutines.md>), [programming](<https://devfeed.tech/tags/programming.md>), [reactive](<https://devfeed.tech/tags/reactive.md>), [reactive-streams](<https://devfeed.tech/tags/reactive-streams.md>), [structured-concurrency](<https://devfeed.tech/tags/structured-concurrency.md>)

### AI overview

This retrospective examines the first year of Structured Concurrency in Kotlin Coroutines. It describes its origins in backend asynchronous programming, adoption in Android lifecycle-aware development, and its role in Kotlin Flows and reactive streams.

### Source excerpt

Photo by Annie Spratt on Unsplash A little over a year ago I announced big conceptual shift in the design of Kotlin Coroutines called Structured Concurrency. From that moment on, it took our team about a month to make the first stable 1.0.0 release of kotlinx.coroutines library. After a year of further work, kotlinx.coroutines had added stable support for cold flows that integrate nicely with reactive streams. The library had reached version 1.3.2 by now. It is good time to look back and see how it all worked out -- what was great, what could be improved. Structured Concurrency accomplished more than we hoped for. Originally, the design of structured concurrency was based on the woes experienced by backend developers trying to implement all sorts of asynchronous and concurrent logic. It was focused on making sure that you cannot ever lose a running coroutine or an exception. The key building block we added back then is coroutineScope { ... } function, which encapsulates concurrent operations and limits their scope to the scope of the current call. There was not much else to it, so our recommendation to UI developers was to implement CoroutineScope interface in various "closeable" entities of their applications. We envisioned a simple picture with a simple scope hierarchy. It turned out to be more elaborate in practice. Structured Concurrency was rapidly adopted by Android, which has quite complicated life-cycles. Android libraries added extensions like lifecycleScope and viewModelScope, enabling concise and safe integration of coroutines with those concepts. It became apparent that code looks clearer when an object encapsulating the scope is separate from the rest of code. Introductory Android Codelab on Coroutines recommends defining coroutine scope like this: private val scope = CoroutineScope(...) Nowadays, this style increasingly looks more appealing, so it's time to adjust our documentation to reflect it. At the same time, structured concurrency laid a solid fou