Coding with Character
realdougwilson.com
realdougwilson.com
> a user needs to easily differentiate between 1, I, |, and l along with 0 and O.
Most of the times, a font present those characters side by side, to show their differences and to illustrate the fact that they can be easily differentiated.
But what we need is not differentiate between them, but identify precisely every single one of them when presented without the other as a comparison point.
Almost every font presented in the article makes that mistake: for example, 0 is almost always the exact same shape and size compared to O, except for a dot or a slash across the 0. This allows you to recognize a 0 at first glance, but not a O. The same issue is also present in a lot of the presented fonts with l that can be mistaken for a 1.
Or I will say "yup, you got me there!" ;-)
I’m pretty anal about that kind of thing. My cloc score is generally about 50% comment-to-code.
But I’m an outlier. Most folks have almost no comments at all in their code.
I guess I could use tabs, instead of spaces, but I’m not interested in doing that.
When I started in this industry, comments were extremely rare and people were consistently pushing to add comments everywhere. Some time later, the pushback came and people started saying that code shouldn't need comments, and if you feel the need to add one... You should rewrite it instead so the code is self explanatory.
Neither side seems to have stopped repeating their points though and there is always a chance to trigger opinionated people into endless discussions just by mentioning comments
All I can say, is that I almost never get questions about my code.
I write about my approach here: https://littlegreenviper.com/miscellany/leaving-a-legacy/
It's a long screed, so no one reads it.
So the rule of thumb for languages like python or ruby is that if you need comments to understand what your code is doing, then you messed up somewhere. Make it easier to read, keep your functions small, and add docstrings. Save your comments for why you're doing something.
But if you're using a less readable language like c, then by all means, comment everything along the way.
I just read a comment I wrote a few years ago that said "I don't know why I have to do it the long way, but it's the only thing that works consistently" over a bit of seemingly verbose code that I would have tried to simplify if I didn't remind myself of that previous struggle.
- Maximum of six characters for any function name. Three characters for the category and three for the actual function. Imagine a code base where every function has a name like strcmp, strlen, etc. So you might have a name like sqlijn for an inner join.
- 80 column line limit, with the first 40 columns reserved for code, and the second 40 columns for a comment. A comment was required on every line of code. So yes indeed, you might see this classic:
++i; /* increment i */
I was hired to build a Windows GUI for the database, and I explained that Windows API functions had much longer names and I was going to run out of room to do much in 40 columns. Thankfully, they gave me special dispensation to follow Windows conventions in the Windows code.Most of my documentation is headerdoc-style stuff, at the opening of methods, or above properties.
I generally don't have much inside methods, unless I think the code is a bit obtuse, and needs a hand.
Then, it's more important for me to document "why," as opposed to "what."
Of course the words "request" and "response" are not the same length. But I thought it would look nice to line things up for a request and its matching response, so I just added an extra space after "request:", like this:
RTO request: {...}
RTO response: {...}
When testing locally in a terminal, this looked great. Everything lined up and was pretty.What I didn't realize was that most people view these logs in New Relic, which does use a monospaced font but does not prevent collapsing of adjacent spaces. So the logs look like this:
RTO request: {...}
RTO response: {...}
Obviously not the end of the world! But it did happen that the first part of the {...} stuff should match between the request and the response, so it made it easier to understand (if it worked) to line them up.I am tempted to change the messages to this, which I think will work around this problem:
RTO request : {...}
RTO response: {...}
Sometimes you can't win for losing!Whoever implemented this in "New Relic" did not think at all about preserving information, which seems critical in a log file.
<p>
Hello
<span>World</span>
doesn't render with a huge number of spaces.I wonder why the creators of New Relic decided to let spaces collapse like that. I can't imagine ever wanting that feature in a monospace font.
SELECT
CAST(CASE WHEN DENY_ADMIN_FILTERS > 0 THEN 0 WHEN ALLOW_ADMIN_FILTERS > 0 THEN 1 END AS bit) CAN_ADMIN_FILTERS,
CAST(CASE WHEN DENY_ADMIN_ACL > 0 THEN 0 WHEN ALLOW_ADMIN_ACL > 0 THEN 1 END AS bit) CAN_ADMIN_ACL,
CAST(CASE WHEN DENY_ADMIN_RML > 0 THEN 0 WHEN ALLOW_ADMIN_RML > 0 THEN 1 END AS bit) CAN_ADMIN_RML,
CAST(CASE WHEN DENY_ADMIN_WORKFLOW > 0 THEN 0 WHEN ALLOW_ADMIN_WORKFLOW > 0 THEN 1 END AS bit) CAN_ADMIN_WORKFLOW,
CAST(CASE WHEN DENY_SET_STATE > 0 THEN 0 WHEN ALLOW_SET_STATE > 0 THEN 1 END AS bit) CAN_SET_STATE,
CAST(CASE WHEN DENY_SHARE > 0 THEN 0 WHEN ALLOW_SHARE > 0 THEN 1 END AS bit) CAN_SHARE,
CAST(CASE WHEN DENY_LINK_PARENTS > 0 THEN 0 WHEN ALLOW_LINK_PARENTS > 0 THEN 1 END AS bit) CAN_LINK_PARENTS,
CAST(CASE WHEN DENY_UNLINK_PARENTS > 0 THEN 0 WHEN ALLOW_UNLINK_PARENTS > 0 THEN 1 END AS bit) CAN_UNLINK_PARENTS,
CAST(CASE WHEN DENY_LINK_CHILDREN > 0 THEN 0 WHEN ALLOW_LINK_CHILDREN > 0 THEN 1 END AS bit) CAN_LINK_CHILDREN,
CAST(CASE WHEN DENY_UNLINK_CHILDREN > 0 THEN 0 WHEN ALLOW_UNLINK_CHILDREN > 0 THEN 1 END AS bit) CAN_UNLINK_CHILDREN,
CAST(CASE WHEN DENY_WRITE > 0 THEN 0 WHEN ALLOW_WRITE > 0 THEN 1 END AS bit) CAN_WRITE,
CAST(CASE WHEN DENY_SEE > 0 THEN 0 WHEN ALLOW_SEE > 0 THEN 1 END AS bit) CAN_SEE,
CAST(CASE WHEN DENY_READ > 0 THEN 0 WHEN ALLOW_READ > 0 THEN 1 END AS bit) CAN_READ,
CAST(CASE WHEN DENY_READ_END > 0 THEN 0 WHEN ALLOW_READ_END > 0 THEN 1 END AS bit) CAN_READ_END
FROM
private_data_iviews.SECURITY_PRECACHE_ACL_INCLUSIVE WITH (NOEXPAND)
WHERE
@acl_id IS NOT NULL
AND @acl_id = ACL_ID
AND @user_id = USER_IDAlso, what's the alternative here? Sure, I could indent everything and make it much more vertical, but that would make things even less readable.
foo(True, True)
foo(False, True)
foo(False, False)
foo(True, False)
Add a few more parameters, put some arithmetic in there that isn't clearly an unrolled double for-loop. Maintaining repetitive code of that form is easier when the arguments are well aligned. And if you're using an editor with a block-select feature, then this changes from an aesthetic preference into a game-changer when you, say, add or remove an argument to foo.They don't solve it. Those spaces to manually-align things are still potentially skewed because it's not fixed-space.
I don't know of any monospace font where O can easily be identified as such and not mistaken with 0.
edit: see a sample here: https://fonts.google.com/specimen/Ubuntu+Mono?category=Monos...
Every character is easily identifiable by itself, except for O. I'm also curious if anyone has a monospace with better identifiably for O and 0.
https://en.wikipedia.org/wiki/Andalé_Mono
edit: I also use monaco which has slashes in zero
In every monospaced font I know, there is a way to identify 0 (the dot or the slash), but not O which could be easily mistaken for a 0.
One of the first problem posted on my problem validation platform was 'Identifying letter O from 0 and vice versa '[1], within couple of days a browser plugin to address the problem was developed by someone else and posted.
It's now my poster for a problem to push down the point that no problem is small.
[1] https://needgap.com/problems/12-identifying-letter-o-from-0-...
- Liberation Sans - metrically compatible with Arial
- Liberation Serif - metrically compatible with Times New Roman
- Liberation Mono - metrically compatible with Courier New
You can read more about them here: https://en.wikipedia.org/wiki/Liberation_fontsIn my experience, Liberation Mono has really good information density while being easy on the eyes and also really readable. In addition, it seems to have pretty good unicode symbol support as well. Also, it remains readable at smaller font sizes as well, which comes in handy if you're working on an enterprise Java code and don't have a really big monitor.
Overall, i'm glad that the font family exists, because it provides a good alternative to having to install MS fonts on *nix systems, which can be annoying at times, plus the fonts are actually included with LibreOffice, which i use nowadays.
The Wikipedia page has a bit more information about the related fonts, but if you'd like to preview something that's a lot like Liberation Mono in the form of a webfont, have a look at Google Cousine: https://fonts.google.com/specimen/Cousine
As for Cousine, it used to be my programming font of choice, but I prefer IBM Plex Mono these days.
I don't mean to begrudge anyone for their preferences. Personally, it just makes very little difference to me. I want a monospace font for coding. If it has the characters I need, which it almost certainly does, then I don't really care about anything else.
If for some reason Apple take umbrage — I can’t think why they would, it isn’t like they haven’t gotten all they could out of me — I would be happy to give them back their laptop.
Sent from my iPhone.
Other requirements are sort of nasty too. MyFonts requires you to embed tracking code into your website to prove you don’t go over your view count
But if you look at independent font developers (who are just folks like you and me), most are perfectly reasonable in pricing and license constraints, and are happy to answer questions or even change the terms and conditions if this makes it easier for you to spend the $30 - $100. I don't think any of these are trying to be litigious, and they're certainly not ignorant.
(Though I understand that your misunderstanding of the web font licensing might make it look so!)
This article is no different -- he covers way too many typefaces and most of them are nothing special.
Usually I look at serif faces and think the serifs are just a noisy distraction. Then I was reading a book that was set in Palatino and I was blown away by the way the serif on the right side of "lowercase r" would almost make love to to the curves of the "lowercase e" and the "lowercase s". I was thinking "gee they got the font metrics right".
Then I looked at the "Palatino linotype" that comes with Windows and the lowercase r is not shaped that way at all.
Since "99% of everything is crap" I want to read articles that cut through the crap and present nothing but the best.
This is intended mostly for my own use case: desktop workstation, light theme, C++ development environment. Though dark theme is also included.
Many caveats exist, there is "About" with disclaimers.
It's somewhat similar to Comic Sans, like the Comic Code from the article, but less playful. It's the most readable programming font I have ever had, with many other typefaces I often see text a little blurry.
Looks like "comic sans-inspired" is a genre. We also have Comic Shans, for example:
But a quick internet search doesn't produce any obvious result proving or disproving that statement. Maybe someone here knows?
Italic fonts traditionally do have more of a handwritten character, but that isn't required. They are distinct fonts of their own, but should be harmonious with the Roman version of the same font.
I love the legibility and the nod to the fact that I am not a computer. I dream of a world where computer code is formatted for humans, not punch card readers.
The Input Manifesto (that's what I'll call it) has a nice explanation of how proportional fonts are beneficial for code:
def mouseMoved(self, info):
point = info["point"]
text = u"%.0f %.0f" % (point.x, point.y)
self.set(text)I do. I like being able to visually spot oddness in statements, and having a sequence of assignments, comparisons, etc lined up makes it easy to spot the lines that do something different.
def mouseMoved(self, info):
point = info["point"]
text = u"%.0f %.0f" % (point.x, point.y)
self.set(text)
Is that any less readable?Urgent request! We need two new variables for some debugging: distance and relative_velocity. Going back to the vertically aligned format, we will add them like this:
def mouseMoved(self, info):
point = info["point"]
text = u"%.0f %.0f" % (point.x, point.y)
distance = self.calculate_distance(info)
relative_velocity = self.calculate_velocity(distance, info)
log_move(point, text, distance, relative_velocity)
self.set(text)
We had to add whitespace to the previous assignments to match the new ones. Now, with all that horizontal whitespace, my eyes have trouble tracking what is assigned to what. And the version control history will have unnecessary formatting diffs.If you forgo the column alignment, those problems go away:
def mouseMoved(self, info):
point = info["point"]
text = u"%.0f %.0f" % (point.x, point.y)
distance = self.calculate_distance(info)
relative_velocity = self.calculate_velocity(distance, info)
log_move(point, text, distance, relative_velocity)
self.set(text)If it's not aligned I have trouble identifying exactly what I need because it's so chaotic. When everything's aligned it's a bit like a table and my brain immediately knows where the right-hand side is no matter which line I want to read.
Now I don't do that everywhere, often it just doesn't bring any benefit. But generally I often find it helpful and it's one of the quickest ways I can make some code blocks more readable, as it takes just a few keypresses.
def mouseMoved(self, info):
point = info["point"]
text = u"%.0f %.0f" % (point.x, point.y)
distance = self.calculate_distance(info)
relative_velocity = self.calculate_velocity(distance, info)
log_move(point, text, distance, relative_velocity)
# Update overlay label
self.set(text)
I find that a much more readable style. Instead of stuff on the left - assigned to stuff on the right, its now a story made up of steps: First we're figuring getting some variables for text labels, and distances. Then logging that out. Then after that we're updating the label on the overlay. Each step in the story has a little breath (the newline). And if needed, a comment.Here's a random work-in-progress example from some real code I'm working on this week. Its not beautiful or overly fancy. Just steady, confident and readable (assuming you know the context):
https://github.com/josephg/diamond-types/blob/2e807298a70382...
I guess it's different between people, I personally find it noticeably slower and more difficult to read like that. Blank lines inbetween don't help because it's about horizontal alignment.
Both approaches emphasise different narratives about the code. The aligned block style emphasises the similarity between the assignments. My space-between-lines style emphasises the difference between each block of code, as if each block is a paragraph it’s own separate intent.
If the assignments were actually similar, I would find the other approach more compelling. Some sibling comments have given better examples where this makes sense. But for this code in particular, the assignments are more different than similar (in both goal and subject). I’d use spacing to make that difference obvious.
const style = {
x : 3,
y : 2,
width : 0,
height : 0,
backgroundColor : 'white',
color : 'black',
fontWeight : 'normal',
shadowStyle : 'none',
borderStyle : 'round'
paddingX : 2,
paddingY : 1,
}Please don't take offense! What works for me doesn't have to be what works for you, OK? :-)
But the insight - if I dare call it that - is that one style leads me to read across each line, where the other style leads me to read down the columns.
In your example, my eyes see an x, a y, a width, a height, a backgroundColor, a color, and so on. And then I see a 3, a 2, a 0, another 0, a 'white', a 'black', etc.
As you can tell, I am reading down the first column, and then reading down the second column. And by then I'm losing track of which thing goes with which.
It's not that I mean to do that, it's just how my eyes are drawn when I see something arranged in columns.
If we reformat this without the column alignment, it looks like this:
const style = {
x: 3,
y: 2,
width: 0,
height: 0,
backgroundColor: 'white',
color: 'black',
fontWeight: 'normal',
shadowStyle: 'none',
borderStyle: 'round'
paddingX: 2,
paddingY: 1,
}
It's definitely not as nice looking this way! But now I read it completely differently:We have an x of 3, a y of 2, a width of 0, a height of 0, a backgroundColor of 'white', a color of 'black', etc.
This style leads me to read across each line instead of down each column. I think that may be why it is easier for me to understand.
And to repeat myself, I am truly grateful to you for posting this example. It helped me get some understanding of what goes on in my eyes and brain.
I use this style also in expressions: often when coding graphics you have similar operations or variables and ordering it in “column fashion” allows quick skimming and error spotting.
Another (real) example:
const neighbors =
get(x - 1, y - 1, w, h, prev) +
get(x, y - 1, w, h, prev) +
get(x + 1, y - 1, w, h, prev) +
get(x - 1, y, w, h, prev) +
get(x + 1, y, w, h, prev) +
get(x - 1, y + 1, w, h, prev) +
get(x, y + 1, w, h, prev) +
get(x + 1, y + 1, w, h, prev)My only suggestion is to be more generous with whitespace inside the parentheses:
const neighbors =
get( x - 1, y - 1, w, h, prev ) +
get( x, y - 1, w, h, prev ) +
get( x + 1, y - 1, w, h, prev ) +
get( x - 1, y, w, h, prev ) +
get( x + 1, y, w, h, prev ) +
get( x - 1, y + 1, w, h, prev ) +
get( x, y + 1, w, h, prev ) +
get( x + 1, y + 1, w, h, prev )
I don't quite understand why, but most modern coding styles prohibit ever putting a space inside the parens. I think the common philosophy is to follow the same conventions you would when writing English prose. But we're not writing prose, we're writing code! To me it is more readable if we allow a little breathing room inside the parens.This looks better in monochrome text but usually the editor colors allow a fast distinction of the parentheses, variables and literals so the extra space is not needed for me.
const neighbors = get(x - 1, y - 1, w, h, prev) + get(x, y - 1, w, h, prev) +
get(x + 1, y - 1, w, h, prev) + get(x - 1, y, w, h, prev) +
get(x + 1, y, w, h, prev) + get(x - 1, y + 1, w, h, prev) +
get(x, y + 1, w, h, prev) + get(x + 1, y + 1, w, h, prev)
In the past, I've resorted to things like adding no-op `+ 0` for alignment and empty comments to force it to preserve line breaks while still allowing it to autoformat the rest: const neighbors = get(x - 1, y - 1, w, h, prev) + //
get(x + 0, y - 1, w, h, prev) + //
get(x + 1, y - 1, w, h, prev) + //
get(x - 1, y + 0, w, h, prev) + //
get(x + 1, y + 0, w, h, prev) + //
get(x - 1, y + 1, w, h, prev) + //
get(x + 0, y + 1, w, h, prev) + //
get(x + 1, y + 1, w, h, prev)
I really wish that autoformatters had the smarts to understand that if more than X% of the non-whitespace columns within a block repeat the same character from top to bottom, then the lines are probably intentionally aligned that way and that it should try very hard to preserve that alignment. That would eliminate my one real objection to autoformatters. (Bonus points for detecting parallel structure in the code and exposing it through alignment in the first place, but that's a much harder generalization of the problem. I'd settle for just leaving that to me and then not destroying it.)Bonus internet points for you today sir.
I don't, and if I tried to, the code formatter would get rid of it anyway.
Given that code formatting is enforced by automated tool, I'm not allowed to use whitespace to align things because the tool decides how stuff should be indented, etc.
The only time I've needed to do any alignment is in comments trying to do some ASCII diagram or something, then I just use the column number to line it up for everyone else.
Monospace fonts now feel... Huge. So much wasted space.
Pragmata Pro, Fantasque Sans Mono, Fira Code, Go Mono, etc.
Definitely expected to see Anonymous or Space Mono on there, though I don't particularly care for either of these myself.
https://madmalik.github.io/mononoki/
Monofur is a wild font I'm mildly surprised was omitted. I did use it full-time for a while maybe 10 years ago, but it's maybe not the best daily driver.
After about an hour, I got depressed and my thoughts went all over the place. "It's karma! You see that 'little' lie you told a couple of years ago about not being responsible for knocking moms pot of soup over? Well, the spirits are paying you back now. Your code is fine boy. But your sins cause it not to work. Maybe you should confess when you get home". Luckily for me, a friend walked into the lab and saw me slouched and with a long face. "What are you coding?" I pointed to the offending line. He looked at it for a few seconds and said "it seems fine... Ah! line 1O should be 10." He corrected it, pressed Shift + F5 and like magic it worked. Now whenever I write code I always put a slash across the zero to indicate it's 0 and not O.
On the other hand, if these fonts were priced at around $5, they drop into the range of an easy, impulse purchase. Even if the creators made substantially less money on each license, I'm sure they'd make more overall from much higher sales.
> I doubt that a programmer who wouldn't spend $100 for a font would spend $5
This is where we disagree then. I think there is a big psychological difference for most consumers, including devs, between spending $5 and $100. Even if you can afford both, the former falls into the range of impulse purchases, like getting a sandwich or a cup of coffee, where you spend without really thinking.
On the other hand, I think a $100 price is far more likely to trigger a more analytical and skeptical response. Do I really need it? Is it worth it? Should I research alternatives? Maybe, I should think about it and decide tomorrow... Etc. And the consequence will be a huge drop in sales.
Also, I also do think there are significant differences in the market for programming fonts vs. general desktop fonts. The market for a single font is likely a relatively small pool of designers / content creators who are spending their employers money, need it to complete a specific project, and who value achieving a unique look. The former is a larger market, who are spending their own money on a nice-to-have, and who don't particularly care about uniqueness.
The price point for fonts is set for people who intend to use the font to make money – like graphic designers. One could imagine a lower price point for private use, similar to media.
The font a programmer uses has absolutely no bearing on the products they produce or the money they make. Unlike graphic design, where a licensed font becomes a direct part of the sold product.
Sure, but 99.9989% aren't going to spend money on programming fonts, period.
I mean, what is next, someone copyrighting the way to pronounce words?
Who created the way we pronounce words? We collectively did, over hundreds of years.
(I do use a font ‘with character’, Fantasque Sans Mono)
I'm totally sold on ligatures too.
For MacOS I've yet to find anything that comes close to Andale Mono.
It feels overkill to get a 4K monitor and scale at 200% just to get nice looking fonts :/
I have long hesitated to pay for fonts for personal, non commercial use. However a well designed font really can make a difference in the usability of a computer. I'm checking these out, I'm at the point where I would be willing to spend some serious cash for a font. Although to me, "serious cash" for a personal use item would be around $25, some of these cost upwards of $100.
Part of my hesitation is a lack of understanding how to analyze fonts and my preference. I've done some reading on typography and design, but any time I install a new font, the depth of my emotion goes as far as "this is nice" or "I liked the previous font more, I guess".
(btw, font licensing in general is a mess)
I find it that it's very easy to get used to ligatures, and I find them strangely satisfying to look at. They're code-specific replacement characters that combine your == into a single long double bar, or -> and => into a neat little arrow character, and so on (link above for more examples). Monoid also has some useful readability tweaks, like bringing together the // or .. character pairs, which are common in many languages. If you're looking to add some quirk and (arguably) readability to your coding, this could be your thing!
Those were the days.
Today I stick with whatever the IDE or distro system font has. Meh.
The only caveat with Cascadia is that it needs fairly high DPI to be nice looking with the bold weight.
* the modern, open source revival → https://github.com/rbanffy/3270font
You may not care what font someone gives you, and that's fine.
But we all have different eyes, different tastes, and different priorities.
I care enough about it to have spent some hours customizing my own personal proportional programming font.
Is that bike shedding? I don't think so. I don't even have a bike!
But in reality, if you did not even have a choice (like we didn't in the olden days), I honestly don't think your productivity would suffer.
I think there other factors that are way more important for that. Like for instance, having syntax highlighting (which hasn't even been around for that long) is in my opinion way more crucial than the choice of font. A way to visualize matching parentheses is way more useful than the choice of font (think Lisp, especially).
So, yeah, nothing wrong with having different tastes.
I'm just saying that the topic of which font you use for programming is way less than important than some people make it out to be, if you believe the internet.
Hey, any other old-timers here? Did that UPPERCASE TEXT make you hear the chunkity-chunk-chunk sound of an Model 33 ASR cranking away at ten characters per second? Cannot be unheard!
I don't know if I am more productive now, but as much as that sound makes me sentimental, I think I am glad to be rid of it.
If I had to pick one to use with a proportional font, I guess it would be Perl. The aesthetics would at least fit it well.
It works because the spaces are nice and wide unlike in a typical proportional font.
I don’t use it anymore mostly because I wanted something with a little more character but it’s worth a try.
that would be horrific! Don't you ever use comments to pin-point to specific parts of a source line?
You may be thinking of Python's "significant whitespace". But all that does is indicate nested blocks.
This works exactly the same in a proportional or monospaced font. The only thing Python cares about is how many spaces or tabs you have at the beginning of a line, and that you don't mix the two.
There are coding styles that don't look as good in a proportional font, such as this kind of "column alignment" or "hanging indent":
def function_with_a_long_name(first_param_with_a_long_name,
second_param_with_a_long_name,
third_param_with_a_long_name):
pass
But you don't have to code like that!The most popular Python code formatter, Black, only uses indentation and no column alignment. Here is how it formats that code:
def function_with_a_long_name(
first_param_with_a_long_name,
second_param_with_a_long_name,
third_param_with_a_long_name,
):
pass
This indentation-based coding style is just as easy to read and write in a proportional font as it is in monospaced.