There are a few significant changes in this new Madeup. In this update, I will focus on one: positional parameters are no longer a thing. In the old Madeup, you could generate a dowel with this code:

```
dowel 10, 45
```

Positional parameters are ordered lists of raw data sent to a function. Here, the positional parameters are 10 and 45. These actual parameters are *implicitly* mapped to the formal parameters of `dowel`

merely by their order of appearance in the call. I think the implicitness of this serial mapping is unfriendly to learners. A first-time reader of code with positional parameters is unlikely to understand it. What do 10 and 45 mean?

The documentation reveals that the first parameter is `maxBend`

, which is used to smooth sharp bends, and the second parameter is `twist`

, which rotates the polygonal cross section of the dowel about its axis. The gulf between the documentation and the editor is not small. The folks who understand positional parameters are the ones who have memorized the API. I want Madeup to be welcoming to those who haven’t.

In the new Madeup, you generate a dowel with *named parameters*:

```
dowel(nsides = 4, round = 10, twist = 45)
```

The names are not optional. This reflects my new philosophy of programming: everything should be named.

Named parameters have benefits. They hint at the meaning of the formerly magic numbers. They can appear in any order, freeing the programmer from having to memorize extraneous details and freeing me from having to lock down the interface of builtin functions in the name of backward compatibility.

Named parameters also have a cost: they make the code longer and more verbose. I want to mitigate this cost, and following are a few of my plans to do so.

Consider the following program, which renders an L-shaped bracket.

Often I build 3D objects in the XY plane, and explicitly setting `z = 0`

in the `moveto`

commands as I do here feels like a waste of time. Therefore I have made a decree. When a parameter has a reasonable default value, that default may be defined in the function definition. A programmer who wishes to employ that default value can omit the parameter from the call. In the following version of the code, we employ the defaults for `z`

, `nsides`

, and `twist`

.

Consider the following program, which renders a column of cubes.

I think that `x = x`

is silly. Therefore I have made a decree. When a variable is passed as an actual parameter to a formal parameter of the same name, the assignment syntax for the parameter is not necessary. It can be written in shorthand as just the shared name. In the following version of the code, we have variables for `x`

, `y`

, and `z`

and our `moveto`

call is much more concise.

We can take that shorthand a step further. If a variable with the same name as a formal parameter is in scope, then we can automatically transfer it along as a parameter—leaving it out of the function call altogether. These are called *implicit parameters*.

In this program, we implicitly pass `y`

to three `moveto`

calls.

Implicit parameters allow us to factor out repetitive code. We set the shared `y`

parameter just once, leaving the `moveto`

calls uncluttered. We clearly see the differences between the calls: the varying `x`

values.

Suppose we have a position `p`

. We could render a sphere centered on this position with the following program.

The syntax here feels clumsy. I have to break down the list manually and spread it across the `x`

, `y`

, and `z`

parameters. How shall we fix this? I could just have `moveto`

accept a list instead of three separate parameters, but I don’t want lists to be a prerequisite for building interesting shapes in Madeup. I could add another version of `moveto`

that accepted a list. Or I could give the existing `moveto`

an alternative `xyz`

or `position`

parameter. Neither of these feels general enough. Therefore I have decreed that we need a splatting syntax for assigning multiple parameters at once from a list.

In this version of the program, we automatically decompose `p`

and pass its elements as values for `x`

, `y`

, and `z`

.

]]>

Fast forward a few years. My oldest son is now 11, I know a little more about electricity, a pandemic has largely bound us to our home, and my younger sons have taken an interest in electricity. These circumstances have led us to extract new life from our forgotten Snap Circuits kit.

The other day my son asked if he could make a diagram of a Snap Circuit. He had seen the Snap Circuits Designer on the Elenco website. The designer is just a Microsoft Word document. Diagrams are made by copying, pasting, dragging, dropping, layering, and finessing. He downloaded it, but we don’t have Microsoft Word and the components are mangled by LibreOffice.

I suggested we make a web app to make designing circuits easier. My son agreed. But as a first step, we need to create scalable images of the components. I gave him a choice of using Inkscape or Twoville. He decided to go with Inkscape, but I’m working alongside him in Twoville.

We call the blue connectors *bridges*. 2-bridges have two snaps, 3-bridges have three snaps, and so on. To show off to my son, I wrote a function that could produce any n-bridge. Here I use it to create several bridges.

It didn’t take me long to write this, and I can easily adjust the design through the global parameters. Nevertheless, my son will finish his versions in Inkscape faster. Time is not a limiting factor for him.

]]>

]]>

The exercise helped me fix an issue with `mirror`

. Previously if the middle vertex was not on the mirror axis, I automatically inserted a straight line segment to bridge the gap between the mirrored segments. That produced more of a Hershey’s Kiss then a raindrop. Now I can insert a cubic Bezier to maintain the curvature.

He wonders aloud about what the most common seven-digit number is. Maybe it’s 1000000 or 9999999? I think to myself that such a question has no answer but then remember I’ve got a duty to develop scientific inquiry in my child. I suggest that we don’t have to guess. We could do a real study of real human beings, asking each one to identify the first seven-digit number that comes to mind. He likes the idea.

We discuss the difficulties of getting a good sample of the population. Perhaps he could ask kids at school? Then I remember that Amazon has a service called Mechanical Turk for getting a bunch of humans to complete tasks that a machine can’t do, like navigating a webpage to test its usability or identifying the contents of images. We make a plan to look into it.

Some weeks later, our stay-at-home orders arrive from our governor, giving us plenty of time together. We set up a *requester* account in Mechanical Turk and figure out how to create a task that asks the workers a single question. There are two tricky parts:

- Validating the form input to only accept a number made of seven digits.
- Wording the question to be short and unambiguous without being leading. We don’t want to include an example of a seven-digit number that a worker could copy and paste.

For a title, we enter “7-digit Number Survey.” For a description, we enter “This is a very simple survey asking you to think of a number. 2 cents for your 2 cents!” We enter this source for the form shown to workers, which includes the validation:

```
<script src="https://assets.crowd.aws/crowd-html-elements.js"></script>
<crowd-form answer-format="flatten-objects">
<div>
<p>Enter a 7-digit number without spaces or punctuation:</p>
<crowd-input id="my-number-input" name="number" required></crowd-input>
</div>
</crowd-form>
<script>
var numberInput = document.getElementById('my-number-input');
var form = document.querySelector('crowd-form');
function validate(event) {
var text = numberInput.value;
if (!text.match(/^\d{7}$/)) {
alert('Your number must be 7 digits and contain no spaces or punctuation.');
event.preventDefault();
}
}
form.addEventListener('submit', validate);
</script>
```

This source produces the following form:

We’re ready to deploy our task, but first we need to decide how many responses we want and how much we want to pay for each response. I pony up $20 for the cause. If we give each human worker $0.02, then we can get 1000 responses. That should be plenty, we think. Amazon asks for an additional $10 fee. I enter a 16-digit number and then our task is live.

The results start flying in. By the end of the first day, we have collected about 500 of the responses. By the end of the second day, 900 responses. By noon on the third day 3, we have our 1000 responses. We take a moment to soak in the data. It is beautiful. It is ours. We quickly dive into analyzing it.

My son is at the computer, and I tell him what code to write. We use Ruby. We load in the table of data, cull the column we want, and sort the numbers.

```
require "csv"
data = CSV.read("7digit.csv", headers: :first_row)
strings = data.map { |row| row["Answer.number"] }
ints = strings.map(&:to_i).sort
```

We keep two versions of the list of numbers: one a list of strings and one a list of equivalent integers. We want both versions because some operations are easier on strings and some are easier on integers. For example, it’s slightly easier to count digits in the string `"0000001"`

than the equivalent integer `1`

.

The low-hanging fruit of our analysis is to count how much of the data was of the proper form, containing exactly seven digits.

```
count7 = strings.count { |n| n.size == 7 }
puts "7 digits: #{count7}"
```

The output makes us cheer.

7 digits: 1000

Our input validation worked. All 1000 responses are usable.

We then determine the minimum and maximum responses.

```
min = strings.min
puts "minimum: #{min}"
max = strings.max
puts "maximum: #{max}"
```

The output is both surprising and unsurprising.

minimum: 0000100 maximum: 9999999

Not a single worker has responded with `0000000`

. We become curious about the other repeating-digit numbers and calculate the frequency of `1111111`

, `2222222`

, and so on.

```
(0..9).each do |i|
count = strings.count { |s| s =~ /^#{i}{7}$/ }
puts "#{i.to_s * 7} -> #{count}"
end
```

The output shows that only `7777777`

gets more than a few hits.

0000000 -> 0 1111111 -> 1 2222222 -> 0 3333333 -> 1 4444444 -> 0 5555555 -> 2 6666666 -> 0 7777777 -> 6 8888888 -> 0 9999999 -> 2

It’s clear that some workers have picked the same number as someone else, but how many?

```
uniqueCount = strings.uniq.size
puts "unique: #{uniqueCount}"
```

The output shows that uniqueness is far more common than duplication.

unique: 876

My son wants to know the sum and average.

```
sum = ints.sum
puts "sum: #{sum}"
average = sum / 1000.0
puts "average: #{average} "
```

The output surprised him.

sum: 4931037193 average: 4931037.193

He is initially perplexed that the sum and average look so similar, but then he remembers how the average is calculated and the result makes sense. If the numbers were uniformly distributed, we’d expect an average of `5000000`

. The average is less than this. Does that mean anything? I don’t know.

We wonder about the median and debate how it should be calculated in a list of even length. My son says if there is no middle number, then it’s the average of the middle two numbers.

```
median = (ints[499] + ints[500]) / 2.0
puts "middle: #{median}"
```

The output shows a median greater than the mean.

middle: 5004019.0

We don’t know if this arrangement of the average and median is significant or not.

Somewhere my son has learned about perfect numbers, which are numbers whose factors sum to the number. Consider 28, whose factors are [1, 2, 4, 7, 14]. Add these up and one gets 28. He wonders if there are any perfect numbers in the data.

```
perfect = ints.select do |n|
(1..n / 2).select { |x| n % x == 0 }.sum == n
end
puts perfect
```

This code runs slowly because we ask each number if it’s perfect by calculating all of its factors and summing them up. We would have been better off collecting a list of all perfect numbers with 7 digits or fewer and just looking for those in the list. Either way, there are no perfect numbers in the responses.

Are people more likely to choose an odd number of an even number?

```
oddcount = ints.count { |n| n % 2 == 1}
puts "odd: #{oddcount}"
```

The output tells us that the odds are for the odds.

odd: 589

We wonder how frequently each digit is seen. This code gets a bit more involved.

```
digits = Hash.new(0)
strings.each do |n|
n.chars.each { |digit| digits[digit] += 1 }
end
digits = digits.sort_by { |n, count| count }.reverse.to_h
digits.each do |n, count|
puts "#{n} -> #{count}"
end
```

In retrospect, I see that a `Hash`

is probably not necessary. An array of 10 counters would have been a bit simpler, but not that much. The output is interesting.

5 -> 838 4 -> 810 7 -> 806 2 -> 758 6 -> 712 3 -> 703 1 -> 678 8 -> 646 9 -> 622 0 -> 427

We are twice as likely to see a 5 as a 0. There’s probably some Freudian explanation for our zero-aversion, but I don’t mention that to my son.

Lastly we examine the frequencies of the complete 7-digit numbers. The code is similar to the code we use to calculate the frequencies of digits.

```
popular = Hash.new(0)
strings.each do |n|
popular[n] += 1
end
popular = popular.sort_by { |n, count| count }.to_h
popular.each do |n, count|
puts "#{n} -> #{count}"
end
```

The output is long, and I include only the numbers that appeared more than once.

2938475 -> 2 6767676 -> 2 5678456 -> 2 6969696 -> 2 1029384 -> 2 6543210 -> 2 5555555 -> 2 8675301 -> 2 1597535 -> 2 1236547 -> 2 9999999 -> 2 1357924 -> 2 2345678 -> 2 7894561 -> 3 7654321 -> 5 9876543 -> 5 7777777 -> 6 1000000 -> 7 8675309 -> 14 1234567 -> 78

Thus we have an answer to our question. `1234567`

is the most popular response by a long shot. My son is very confused by the runner-up `8675309`

, but I delay explaining to him what it means to children of the 1980s in hopes that he will investigate. He asks his brothers if they know the number, but they are all younger than him. `1000000`

is the first number that truly requires all seven digits, so it has significance to us. `7777777`

must be doubly lucky, or septuply perhaps. `9876543`

and `7654321`

are just decreasing sequences. That `7894561`

occurs three times strikes us as peculiar, but then we see that it too is a sequence. It is the arrangement of numbers on a 10-key keypad. I’m fairly sure `8675301`

appears because people mishear lyrics as they’re using the bathroom on the right. Many of the rest are increasing or decreasing sequences. My son gets no help from me figuring out `6969696`

. We assume that `2938475`

and `1029384`

are just flukes, but we are disturbed that they have `29384`

in common. In writing this, we see that these numbers are not flukes at all. They are shaped by typing from either end of the top row of the keyboard, working inward and alternating between strokes.

In conclusion, my son and I feel great about having a question, gathering data, and analyzing the results. That we administered this survey through a computer is clear. Many of the most frequent numbers were clearly chosen because of typing ergonomics. Perhaps we need to do a face-to-face survey to get results that aren’t tainted by our technological interfaces. But not until the governor says we can.

]]>

Select the rectangle and you’ll see controls appear. Click and drag on them to change the size or corner position. That’s direct manipulation.

Initially, we thought to just update the geometric property, which we’ll call $p$, by replacing its original value completely with a new value derived from the mouse position, like this:

$$\begin{gather}p = \textrm{old value} \\\downarrow \\p = \textrm{new value} \\\end{gather}$$

This simplistic replacement scheme seemed reasonable until the expressions got more complicated. Suppose the property $p$ was the result of a sum.

$$\begin{gather}p = a + b\end{gather}$$

Should the entire $a + b$ expression be replaced with a new value derived from the mouse position, abandoning the addition operation? Or should we be more selective about what we update? We have decided to be more selective. The $+$ must have some semantic meaning to the designer, and we want to preserve it.

I now enumerate the kinds of expressions we target and describe how we selectively update them. You can probably stop reading. The primary audience of this post is my collaborator and me.

When the expression is a number, we just replace it with a value derived from the mouse position. This is the only situation in which we replace the entire expression.

When the expression is an addition operation, and the right operand is a number, we update only the right operand—no matter what the left operand is. For instance, the expression could be $n + 2$. We assume that 2 is some magic number waiting to be tweaked.

We know that the property is computed as $a + b$. We have $p$ from the mouse position and $a$ unchanged from the original expression. From these we can solve for the new $b$.

$$\begin{align}p &= a + b \\b &= a – p \\\end{align}$$

When the expression is an addition operation, the right operand is more complex than a number, and the left-operand is a number, we update only the left operand. For instance, the expression could be $2 + n$. We assume that 2 is some magic number waiting to be tweaked.

We know that the property is computed as $a + b$. We have $p$ from the mouse position and $b$ unchanged from the original expression. From these we can solve for the new $a$.

$$\begin{align}p &= a + b \\a &= p – b \\\end{align}$$

When the expression is a multiplication and the right operand is a number, we update only the right operand—just as with addition. We compute the new $b$ from the mouse position and the unchanged left operand $a$.

$$\begin{align}p &= a \times b \\b &= \frac{p}{a} \\\end{align}$$

But what do we do if $a$ evaluates to a 0? My current leaning is to fall through to the default case described below.

When the expression is a multiplication, the left operand is a number, and the right operand is more complex than a number, we update only the left operand—just as with addition. We compute the new $a$ from the mouse position and the unchanged right operand $b$.

$$\begin{align}p &= a \times b \\a &= \frac{p}{b} \\\end{align}$$

But what do we do if $b$ evaluates to a 0? My current leaning is to fall through to the default case described below.

When the expression is a subtraction and the right operand is a number, we update only the right operand. We compute the new $b$ from the mouse position and the unchanged left operand $a$.

$$\begin{align}p &= a – b \\b &= a – p \\\end{align}$$

When the expression is a subtraction, the left operand is a number, and the right operand is more complex than a number, we update only the left operand. We compute the new $a$ from the mouse position and the unchanged right operand $b$.

$$\begin{align}p &= a – b \\a &= p + b \\\end{align}$$

When the expression is a division and the right operand is a number, we update only the right operand. We compute the new $b$ from the mouse position and the unchanged left operand $a$.

$$\begin{align}p &= \frac{a}{b} \\b &= \frac{a}{p} \\\end{align}$$

But what if $p$ is 0? My current leaning is not let the manipulation update the expression in this case. As the mouse keeps moving, $p$ will keep updating and we may re-enter defined territory.

When the expression is a division, the left operand is a number, and the right operand is more complex than a number, we update only the left operand. We compute the new $a$ from the mouse position and the unchanged right operand $b$.

$$\begin{align}p &= \frac{a}{b} \\a &= \frac{p}{b} \\\end{align}$$

But what if $b$ evaluates to 0? My current leaning is to fall through to the default case described below.

When the expression is an exponentiation and the right operand is a number, we update only the right operand. We compute the new $b$ from the mouse position and the unchanged left operand $a$.

$$\begin{align}p &= a^b \\\log p &= \log a^b \\ &= b \log a \\b &= \frac{\log p}{\log a} \\\end{align}$$

But what if $a$ is 1? We’ll have $\log 1 = 0$ in the demoninator. There’s no way to raise 1 to an arbitrary value. My current leaning is to fall through to the default case described below.

When the expression is an exponentiation, the left operand is a number, and the right operand is more complex than a number, we update only the left operand. We compute the new $a$ from the mouse position and the unchanged right operand $b$.

$$\begin{align}p &= a^b \\\sqrt[b]{p} &= \sqrt[b]{a^b} \\a &= \sqrt[b]{p} \\\end{align}$$

But what if $b$ evaluates to 0? An exponent of 0 can only produce the value 1. My current leaning is to fall through to the default case described below.

If the expression matched none of the above cases, then instead of replacing the expression with a value derived from the mouse position, we preserve the designer’s original expression but tack on an offset $\Delta$. We compute the new $\Delta$ from the mouse position and the unchanged expression $e$.

$$\begin{align}p &= e + \Delta \\\Delta &= p – e \\\end{align}$$

This case kicks in when the above rules land in undefined waters or when the expression is a function call like $\cos x$, a subscript into a collection, or some other crazy operation.

]]>JJK frequently profiles the work of his illustrator friends, and in episode 33, Joyce Wan taught us how to draw a cute donut. The drawing inspired our hunger but also our creativity. I decided to try and recreate my donut in Twoville. Here is the result:

It’s happy because I can’t eat it.

]]>Perhaps there are days whose rational numbers are closer? I had to find out, so I wrote a program. I’m gun-shy of date libraries, so I started with just this simple list of month lengths:

```
MONTH_LENGTHS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
YEAR_LENGTH = MONTH_LENGTHS.sum
```

I hardcoded February as a non-leap year.

Next up, because I like pivoting around data rather than code, I modeled the subject of our study using a class. Its methods interpret the date as various rational numbers: as a month-over-day, as a day-of-year, and as a day-over-month.

```
class Date
attr_reader :month, :day, :doy
def initialize(month, day, doy)
@month = month
@day = day
@doy = doy
end
def doyProportion
@doy.to_f / YEAR_LENGTH
end
def monthOverDay
@month.to_f / @day
end
def dayOverMonth
@day.to_f / @month
end
end
```

To make a list of all the dates of the year, I decided to iterate through the interval [1, 365], maintaining separate month and day counters as I go. Upon reaching the end of month, I reset the day counter back to 1.

```
doy = 1
month = 1
day = 1
dates = []
while month < 13
dates << Date.new(month, day, doy)
doy += 1
if day < MONTH_LENGTHS[month - 1]
day += 1
else
day = 1
month += 1
end
end
```

Now I had all the pieces I needed to conduct my investigation. I sorted my list by the absolute difference between the month-over-day and the day-of-year proportion:

```
sorted = dates.sort_by do |date|
(date.monthOverDay - date.doyProportion).abs
end
```

Who do you think the winner was?

…

…

…

…

…

…

…

…

Spoilers ahead.

…

…

…

…

…

…

…

…

In Table 1, we have the top ten dates whose month-over-days are nearest to their day-of-year proportions.

date | day of year | month-over-day | day-of-year proportion | difference |
---|---|---|---|---|

1/19 | 19 | 0.0526 | 0.0521 | 0.0006 |

4/14 | 104 | 0.2857 | 0.2849 | 0.0008 |

8/13 | 225 | 0.6154 | 0.6164 | 0.0011 |

3/15 | 74 | 0.2000 | 0.2027 | 0.0027 |

2/16 | 47 | 0.1250 | 0.1288 | 0.0038 |

1/20 | 20 | 0.0500 | 0.0548 | 0.0048 |

1/18 | 18 | 0.0556 | 0.0493 | 0.0062 |

7/13 | 194 | 0.5385 | 0.5315 | 0.0070 |

2/15 | 46 | 0.1333 | 0.1260 | 0.0073 |

9/13 | 256 | 0.6923 | 0.7014 | 0.0091 |

Congratulations, January 19! Adding in the leap day changes this list very little.

Which dates do you think had the largest differences between their two rational numbers? You don’t really need a program to tell you the answers, which are shown in Table 2.

date | day of year | month-over-day | day-of-year proportion | difference |
---|---|---|---|---|

11/2 | 306 | 5.5 | 0.8384 | 4.6616 |

5/1 | 121 | 5.0 | 0.3315 | 4.6685 |

12/2 | 336 | 6.0 | 0.9205 | 5.0795 |

6/1 | 152 | 6.0 | 0.4164 | 5.5836 |

7/1 | 182 | 7.0 | 0.4986 | 6.5014 |

8/1 | 213 | 8.0 | 0.5836 | 7.4164 |

9/1 | 244 | 9.0 | 0.6685 | 8.3315 |

10/1 | 274 | 10.0 | 0.7507 | 9.2493 |

11/1 | 305 | 11.0 | 0.8356 | 10.1644 |

12/1 | 335 | 12.0 | 0.9178 | 11.0822 |

Congratulations, December 1!

America is one of the few countries that places months before days in dates. Sometimes the month-day-year ordering is called *middle-endian* ordering. Many more countries use *little-endian* ordering. They would say that today is 28/4.

Let’s examine figure out which dates are closest in little-endian ordering. We make just a slight change to our sorting criteria to consider the day-over-month rather than the month-over-day:

```
sorted = dates.sort_by do |date|
(date.dayOverMonth - date.doyProportion).abs
end
```

The dates whose rational numbers are nearest are shown in Table 3.

date | day of year | day-over-month | day-of-year proportion | difference |
---|---|---|---|---|

1/4 | 91 | 0.2500 | 0.2493 | 0.0007 |

6/9 | 249 | 0.6667 | 0.6822 | 0.0155 |

11/12 | 345 | 0.9167 | 0.9452 | 0.0285 |

8/10 | 281 | 0.8000 | 0.7699 | 0.0301 |

5/8 | 217 | 0.6250 | 0.5945 | 0.0305 |

9/11 | 313 | 0.8182 | 0.8575 | 0.0394 |

10/11 | 314 | 0.9091 | 0.8603 | 0.0488 |

12/12 | 346 | 1.0000 | 0.9479 | 0.0521 |

4/7 | 185 | 0.5714 | 0.5068 | 0.0646 |

2/5 | 122 | 0.4000 | 0.3342 | 0.0658 |

Congratulations, 1 April!

Once again, can you guess which dates are at the bottom of this list? You can, if you believe in yourself. The answers are shown in Table 4.

date | day of year | day-over-month | day-of-year proportion | difference |
---|---|---|---|---|

22/1 | 22 | 22.0 | 0.0603 | 21.9397 |

23/1 | 23 | 23.0 | 0.063 | 22.937 |

24/1 | 24 | 24.0 | 0.0658 | 23.9342 |

25/1 | 25 | 25.0 | 0.0685 | 24.9315 |

26/1 | 26 | 26.0 | 0.0712 | 25.9288 |

27/1 | 27 | 27.0 | 0.074 | 26.926 |

28/1 | 28 | 28.0 | 0.0767 | 27.9233 |

29/1 | 29 | 29.0 | 0.0795 | 28.9205 |

30/1 | 30 | 30.0 | 0.0822 | 29.9178 |

31/1 | 31 | 31.0 | 0.0849 | 30.9151 |

Congratulations, 31 January!

I am satisfied with the outcome of my investigation. I now have four new holidays to celebrate.

]]>We could go with labels on the left and inputs on the right—with a grid to keep everything aligned. But the labels will have various lengths. Do we right-align them against the inputs, leaving a ragged axis on the left? Or do we left-align them, leaving internal space between the shortest labels and the inputs?

Or we could go with labels and inputs all in one vertical stack. The danger with this arrangement is ambigous visual parsing. Does a label associate with the input above it or below it?

I think neither approach is good. Both suffer from separateness. The label and input are distinct elements. Why not just put the label and the input in the same box? That’s easy enough to do in HTML.

```
<label class="infield">
<span>Name</span>
<input type="text">
</label>
<label class="infield">
<span>Regrets</span>
<input type="text">
</label>
<label class="infield">
<span>Birth Order</span>
<input type="text" class="number-input">
</label>
```

But these label-input pairs are very much separated when this HTML is rendered. We can hide this separateness with some CSS that visually blends the `label`

, `span`

, and `input`

together. We strip out all of the `input`

decorations and make the `label`

look like one big box that we can type in. Really the `label`

is just a vertical stack of its two children.

```
.infield {
margin-top: 10px;
display: flex;
flex-direction: column;
padding: 5px;
border: 1px solid darkgray;
border-radius: 3px;
outline-width: 3px;
outline-offset: -2px;
background-color: #F6F6F6;
box-shadow: inset 0 0 2px #999999;
}
.infield > span {
color: darkgray;
font-family: sans-serif;
font-size: 12px;
margin-bottom: 5px;
}
.infield > input {
border: none;
outline: none;
background: none;
font-size: 16px;
}
```

We end up with the form shown in Figure 1.

What about our outline? Usually the browser shows us what form element we are focused on. Well, if we have `:focus-within`

, we can apply the outline to the surrounding `label`

.

```
.infield:focus-within {
outline-color: blue;
outline-style: auto;
}
.infield:focus-within > span {
font-weight: bold;
color: blue;
}
```

The form shown in Figure 2 is more like what we are used to.

Perhaps we could highlight the fields when something has been entered, or when something has been entered incorrectly. Let’s add some styles for these two states.

```
.infield:focus-within > span, .infield.non-empty > span {
color: blue;
font-weight: bold;
}
.infield.error {
outline-color: red;
outline-style: auto;
background-color: #FFEEEE;
}
.infield.error > span {
color: red;
font-weight: bold;
}
```

Some JavaScript is needed to dynamically add or remove these classes when the user types in the boxes.

```
const infields = document.querySelectorAll('.infield');
for (let infield of infields) {
const input = infield.children[1];
input.addEventListener('input', () => {
infield.classList.toggle('non-empty', input.value.length > 0);
});
if (input.classList.contains('number-input')) {
input.addEventListener('input', () => {
infield.classList.toggle('error', input.value.length > 0 && !input.value.match(new RegExp('^\\d+$')));
});
}
}
```

There we have it! A form that is clearly labeled and easy to align. All that’s left is to put a really big Submit button below it, as we see in Figure 4.

]]>The other day my son stumbled upon this numerical curiosity:

$$3 \times 1.5 = 3 + 1.5$$

How fascinating that the numbers don’t care whether they are being added or multiplied. Both operations yield the same result.

My son eagerly reported his discovery to me. I wondered out loud with him if there are other numbers that don’t care about whether they are being added or multiplied, and we worked out this relationship:

$$\begin{eqnarray}a \times b &=& a + b \\a \times b – b &=& a \\b \times (a – 1) &=& a \\b &=& \frac{a}{a – 1} \\\end{eqnarray}$$

It looks like we can choose any number $a \neq 1$ and calculate its mate as $\frac{a}{a – 1}$. Choosing $a = 3$ gives us the pair $(3, \frac{3}{2})$. We also have $(4, \frac{4}{3})$, $(5, \frac{5}{4})$, and so on.

As Asimov writes in *Realm of Numbers*, mathematicians like to give names to numbers or sets of numbers that have certain properties. We are calling numbers that don’t care whether they are being added or multiplied *apathetic numbers*.

My son went away giddy.

]]>