PurelyFunctional.tv Newsletter 420: Say what you mean

Issue 420 - March 29, 2021 · Archives · Subscribe

Design Tip 💡

Say what you mean

People have tried to write a "more concise Java," like Groovy. But I think the idea is misguided. The fundamental problem is not that Java is verbose. The design flaw is that Java does not allow you to say what you mean directly. Instead, you have to translate your ideas into the language's model.

People often rightly criticize Java for being verbose. It's crazy verbose. People have tried to address that verbosity by reducing the amount of redundancy. For example, in Java:

import java.io.*;

. . .

File f = new File("essay.txt");

We could start to pick at it and identify the redundant parts. Do we really need to say File twice? Do we really need a new line and a semi-colon? Do we really need to import the most common packages explicitly? We could start tweaking the language to make it shorter. Groovy takes this approach (along with fixing a few warts of Java).

Redundancy is part of the issue, but when I say "very concise Java," that doesn't scream "well-designed language." Why not?

Let's analyze the situation. There's a Java programmer, June, who has a good idea about the isA and hasA relationships that she wants to program. June needs to choose the Java semantics to express those ideas. And then must select the Java syntax to invoke those semantics. That's three relevant nodes on a path:

  1. The programmer's idea
  2. The semantics (what the program means to the computer)
  3. The syntax

Of course, the software starts at 1, goes to 2, then finishes at 3. I believe that the quality of a design is how direct that path is.

If June wants to indicate an isA relationship (a fundamental concept in Object-Oriented Design (OOD)), she needs to translate that into "class inheritance," which is part of the Java semantics. To do that, she writes the extends keyword. How far is her original idea (isA) from the syntax she wrote (extends)? They are different words, but it's only one small step.

class Admin extends User {

If June wants to indicate a hasA relationship (another fundamental OOD idea), she needs to translate that into an instance field and ensure that she properly initializes it. The syntax looks like a variable declaration in the scope of the class. And the initialization is an assignment in the constructor. That's a lot of steps between hasA and the code.

class Admin extends User {
  private String adminID;

  public Admin(String adminID) {
    this.adminID = adminID;

Now, June wants to indicate a hasMany relationship. She needs to translate that idea into Java semantics: an instance field which refers to a collection. She needs to initialize the field by constructing the collection. The syntax for this is complicated: an instance field declaration, an assignment in the constructor, a new keyword to construct the collection. This is not to mention the accessors needed to add and remove items from the relationship. The end result is very far from the desired hasMany.

class Admin extends User {
  private String adminID;
  private Set<User> subaccounts;

  public Admin(String adminID) {
    this.adminID = adminID;
    subaccounts = new Set<User>();

The further the end syntax is from the original idea, the worse the design is.

The word further is subjective and lacks a good metric. I hope to improve on that, but I'll stick with it for now.

How would you improve the design of Java? First, we must qualify that. Design always has a problem to solve. So we must say, "How would you improve the design of Java for expressing Object-Oriented Design?" I don't like OOD. I'm not endorsing it. But that problem statement doesn't sound like it's too far-fetched for the purpose of Java programmers.

Well, shorten the distance. If your design paradigm has an isA idea, make an isA feature and use the same word as your syntax.

class Admin isA User {

(Let's leave other parts of the language alone for now and address just one problem at a time.)

Then, do the same for hasA:

class Admin isA User {
  hasA String adminID;

Then you can do it for hasMany:

class Admin isA User {
  hasA String adminID;
  hasMany User subaccounts;

Gosh, that almost looks refreshing.

I think the reason we like Haskell and Clojure is that they are more direct. Yes, they are concise. However, the real benefit is that Clojure programmers make a tiny hop from "Entity" to "hash map," then they write the syntax for a hash map. Haskell programmers want a type to express alternatives, and they declare a discriminated union. There's room to improve, but it's way more direct.

There are many factors in language design. However, I think this idea of directness is often overlooked. We talk about concision. We talk about removing programmer burden (as in garbage collection). But we don't speak about directness, otherwise known as "say what you mean." Directness makes me wonder why Domain-Driven Design doesn't write their own language. They've got lots of new terms, but what language has a semantic feature called bounded context? And how could it help the design of Clojure? Next time, folks!

Podcast episode🎙

This week on the podcast, I talk about the false nominalization of the verb design. Check it out: Is design a noun or a verb?

Book update ✍️

DON'T STOP THE PRESSES!

Grokking Simplicity is at the printer's! Although I won't relax until the book is in my hands, this is a big step.

Here's the schedule they've given me. All dates are approximate.

  • The final PDF will be available on Manning's site on about April 2.
  • The print book will be shipped to those who ordered it during MEAP around April 16-April 23, plus or minus shipping times. It will be available on Amazon around that time as well.
  • ePub and Kindle versions will be available on about April 16. It's included in the price of the print book (even from Amazo n). However, I can't recommend these versions. I have not seen them and I worked hard on the layout of each page. I have a bad feeling it won't translate well to the Kindle layout engine. I'll keep you posted.
  • I'm told you can also get it on O'Reilly Online and Apple Store April 23-30. Again, I can't vouch for these versions.

However, you can buy Grokking Simplicity on Manning's site today and use the coupon code TSSIMPLICITY for 50% off. You can buy it now and it will be shipped to you when it's printed. Meanwhile, you can read the PDF version today!

Thanks to those of you who have already purchased 😘

Currently recording 🎥

I am now ready to talk about my next project: a course in how to build a Clojure web stack from scratch.

In Clojure, we often build a web stack out of existing parts of our own choosing. That's definitely valuable for learning. But what do you learn? In my experience, the most important thing you learn is a deep and practical understanding of the HTTP protocol. You have to, in fact, or you wouldn't be able to put it together yourself. So that's what we're learning in the course. We'll build a web application, piece by piece, and learn how each part plays a role in the protocol.

I'm still working on it and I'll share more as it becomes ready.

Podcast appearances 📢

I was very honored to speak on JS Party and Does Not Compute, two programming podcasts. I got to spread the word about functional programming.

Quarantine update 😷

I know a lot of people are going through tougher times than I am. If you, for any reason, can't afford my courses, and you think the courses will help you, please hit reply and I will set you up. It's a small gesture I can make, but it might help.

I don't want to shame you or anybody that we should be using this time to work on our skills. The number one priority is your health and safety. I know I haven't been able to work very much, let alone learn some new skill. But if learning Clojure is important to you, and you can't afford it, just hit reply and I'll set you up. Keeping busy can keep us sane.

Stay healthy. Wash your hands. Wear a mask. Take care of loved ones.

Clojure Challenge 🤔

Last issue's challenge

Issue 419

Please do participate in the discussion at the submission links above. It's active and it's a great way to get comments on your code.

This week's challenge

Unique elements

There's a function in Clojure called distinct that removes duplicates from a sequence. Your task is to write a function called uniques that removes elements that appear twice.

Examples

(uniques []) ;=> ()
(uniques [1 2 3]) ;=> (1 2 3)
(uniques [1 1 2 3]) ;=> (2 3)
(uniques [1 2 3 1 2 3]) ;=> ()
(uniques [1 2 3 2]) ;=> (1 3)

Thanks to this site for the challenge idea where it is considered Medium in Python. The problem has been modified from the original.

Please submit your design process as comments to this gist. Discussion is welcome.

Rock on!
Eric Normand