> Originally, if you typed an unknown command, it would just say "this is not a git command".
Back in the 70s, Hal Finney was writing a BASIC interpreter to fit in 2K of ROM on the Mattel Intellivision system. This meant every byte was precious. To report a syntax error, he shortened the message for all errors to:
EH?
I still laugh about that. He was quite proud of it.
I feel like that would also make a good response from the text parser in an old-school interactive fiction game.
Slightly related, but I remember some older variants of BASIC using "?" to represent the PRINT statement - though I think it was less about memory and more just to save time for the programmer typing in the REPL.
It was about saving memory by tokenizing keywords: '?' is how PRINT actually was stored in program memory, it just rendered as 'PRINT'. Most other tokens were typically the first two characters, the first lowercase, the second uppercase: I remember LOAD was 'lO' and DATA was 'dA', though on the C64's default character glyphs they usually looked like L<box char HN won't render> and D<spade suit char>.
All this being on a C64 of course, but I suspect most versions of Bill Gates's BASIC did something similar.
Ed also uses "?" for "Are you sure?" If you're sure, you can type the last command a second time to confirm.
The story goes that ed was designed for running over a slow remote connection where output was printed on paper, and the keyboard required very firm presses to generate a signal. Whether this is true or folklore, it would explain a lot.
GNU Ed actually has optional error messages for humans, because why not.
There are really few systems where you can save a part of a byte! And if you need to output a byte anyway, it doesn't matter which byte it is. So you can indulge and use "?", "!", "*", or even "&" to signify various types of error conditions.
(On certain architectures, you could use 1-byte soft-interrupt opcodes to call the most used subroutine, but 8080 lacked it IIRC; on 6502 you could theoretically use BRK for that. But likely you had other uses for it than printing error diagnostics.)
He wasn't hacking. Hal worked for Aph, and Aph contracted with Mattel to deliver console game cartridges.
There was once a contest between Caltech and MIT. Each was to write a program to play Gomoku, and they'd play against each other. Hal wrote a Gomoku-playing program in a weekend, and it trashed MIT's program.
I run a wordle spinoff, xordle, which involves two wordle puzzles on one board. This means you can guess a word and get all 5 letters green, but it isn't either of the target words. When you do this it just says "Huh?" on the right. People love that bit.
If the original setting had been named something bool-y like `help.autocorrect_enabled`, then the request to accept an int (deciseconds) would've made no sense. Another setting `help.autocorrect_accept_after_dsec` would've been required. And `dsec` is so oddball that anyone who uses it would've had to look up.
I insist on this all the time in code reviews. Variables must have units in their names if there's any ambiguity. For example, `int timeout` becomes `int timeout_msec`.
This is 100x more important when naming settings, because they're part of your public interface and you can't ever change them.
> I insist on this all the time in code reviews. Variables must have units in their names if there's any ambiguity. For example, `int timeout` becomes `int timeout_msec`.
Same here. I'm still torn when this gets pushed into the type system, but my general rule of thumb in C++ context is:
void FooBar(std::chrono::milliseconds timeout);
is OK, because that's a function signature and you'll see the type when you're looking at it, but with variables, `timeout` is not OK, as 99% of the time you'll see it used like:
auto timeout = gl_timeout; // or GetTimeoutFromSomewhere().
FooBar(timeout);
Common use of `auto` in C++ makes it a PITA to trace down exact type when it matters.
(Yes, I use IDE or a language-server-enabled editor when working with C++, and no, I don't have time to stop every 5 seconds to hover my mouse over random symbols to reveal their types.)
One of my favorite features of std::chrono (which can be a pain to use, but this part is pretty sweet) is that you don't have to specify the exact time unit, just a generic duration. So, combined with chrono literals, both of these work just like expected:
std::this_thread::sleep_for(10ms); // sleep for 10 milliseconds
std::this_thread::sleep_for(1s); // sleep for one second
std::this_thread::sleep_for(50); // does not work, unit is required by type system
That's such a cool way to do it: instead of forcing you to specify the exact unit in the signature (milliseconds or seconds), you just say that it's a time duration of some kind, and let the user of the API pick the unit. Very neat!
It should not matter though, because std::chrono is not int-convertible - so is it "milliseconds" or "microseconds" or whatever is an minor implementation detail.
You cannot compile FooBar(5000), so there is never confusion in C++ like C has. You have to do explicit "FooBar(std::chrono::milliseconds(500))" or "FooBar(500ms)" if you have literals enabled. And this will handle conversion if needed - you can always do FooBar(500ms) and it will work even if actual type in microseconds.
Similarly, your "auto" example will only compile if gl_timeout is a compatible type, so you don't have to worry about units at all when all your intervals are using std::chrono.
Right, your type system can quickly become unwieldy if you try to create a new type for every slight semantic difference.
I feel like Go strikes a good balance here with the time.Duration type, which I use wherever I can (my _msec example came from C). Go doesn’t allow implicit conversion between types defined with a typedef, so your code ends up being very explicit about what’s going on.
> Yes, I use IDE or a language-server-enabled editor when working with C++, and no, I don't have time to stop every 5 seconds to hover my mouse over random symbols to reveal their types.
JetBrains does a great thing where they show types for a lot of things as labels all the time instead of having to hover over all the things.
Yes and it's made worse by using "deciseconds," a unit of time I've used literally 0 times in my entire life. If you see a message saying "I'll execute in 1ms," you'd look straight to your settings!
> Then you end up with something where you can write "TimoutSec=60" as well as "TimeoutSec=1min" in the case of systemd :)
But that's wrong too! If TimeoutSec is an integer, then don't accept "1min". If it's some sort of duration type, then don't call it TimeoutSec -- call it Timeout, and don't accept the value "60".
That’s not automatically bad. There are two kinds of Hungarian notation: systems Hungarian, which duplicates information that the type system should be tracking; and apps Hungarian, which encodes information you’d express in types if your language’s type system were expressive enough. [1] goes into the difference.
> I insist on this all the time in code reviews. Variables must have units in their names if there's any ambiguity. For example, `int timeout` becomes `int timeout_msec`.
Personally I flag any such use of int in code reviews, and instead recommend using value classes to properly convey the unit (think Second(2) or Millisecond(2000)).
This of course depends on the language, it's capabilities and norms.
I agree. Any time we start annotating type information in the variable name is a missed opportunity to actually use the type system for this.
I suppose this is the "actual" problem with the git setting, in so far as there is an "actual" problem: the variable started out as a boolean, but then quietly turned into a timespan type without triggering warnings on user configs that got reinterpreted as an effect of that.
Yes! As it is, '1' is ambiguous, as it can mean "True" or '1 decisecond', and deciseconds are not a common time division. The units commonly used are either seconds or milliseconds. Using uncommon units should have a very strong justification.
Though, ironically, msec is still ambiguous because that could be milli or micro. It's often milli so I wouldn't fault it, but we use micros just enough at my workplace where the distinction matters. I would usually do timeout_micros or timeout_millis.
We use "ms" because it's the standard SI symbol. Microseconds would be "us" to avoid the µ.
In fact, our French keyboards do have a "µ" key (as far as I remember, it was done so as to be able to easily write all SI prefixes) but using non-ASCII symbols is always a bit risky.
> Now, why Junio thought deciseconds was a reasonable unit of time measurement for this is never discussed, so I don't really know why that is.
xmobar uses deciseconds in a similar, albeit more problematic place - to declare how often to refresh each section. Using deciseconds is fantastic if your goal is for example configs to have numbers small enough that they clearly can't be milliseconds, resulting in people making the reasonable assumption that it must thus be seconds, and running their commands 10 times as often as they intended to. I've seen a number of accidental load spikes originating from this issue.
EDIT: 1) is the result of my misreading of the article, the "previous value" never existed in git.
1) Pushing a change that silently break by reinterpreting a previous configuration value (1=true) as a different value (1=0.100ms confirmation delay) should pretty much always be avoided. Obviously you'd want to clear old values if they existed (maybe this did happen? it's unclear to me), but you also probably want to rename the configuration label..
2) Having `help.autocorrect`'s configuration argument be a time, measured in a non-standard (for most users) unit, is just plainly bad. Give me a boolean to enable, and a decimal to control the confirmation time.
For point 1, I think you're misunderstanding the timeline. That change happened in 2008, during code review of the initial patch to add that option as a boolean, and before it was ever committed to the main git tree.
Someone thought of a feature (i.e. configurable autocorrect confirmation delay) and decided the interface should be identical to an existing feature (i.e. whether autocorrect is enabled). In my thinking, that second part is "design" of the interface.
IMHO this is a great example of "creeping featurism". At best it introduces unnecessary complexity, and at worst those reliant on it will be encouraged to pay less attention to what they're doing.
What I don't get is why anyone would want to allow the automation. Is it really that difficult to use the up-arrow key and correct the mistake? Doing something automatically when it's sort-of correct is a recipe for doing things you didn't intend to do.
Double this. If I don't type the command that I want, I never want my computer guessing and acting on that guess. Favors like that are why I hate Microsoft Word ("Surely you didn't mean XXXX; I'll help you by changing it to YYYY. Oh, you did it again, and in the same place? Well, I'll fix it again for you. High five!")
> Which was what the setting value was changed to in the patch that was eventually accepted. This means that setting help.autocorrect to 1 logically means "wait 100ms (1 decisecond) before continuing".
The mistake was here. Instead of retargeting the existing setting for a different meaning, they should have added a new setting.
help.autocorrect - enable or disable
help.autocorrect.milliseconds - how long to wait
There are similar mistakes in other systems, e.g., MySQL has
innodb_flush_log_at_trx_commit
which can be 0 if disabled, 1 if enabled, and 2 was added as something special.
The “real” issue is an untyped configuration language which tries to guess at what you actually meant by 1. They’re tripling down on this by making 1 a Boolean true but other integers be deciseconds. This is the same questionable logic behind YAML’s infamous “no” == false.
Not sure where the best place to mention would be, but 0.1 deciseconds is not unreasonable, either...yes fastest recorded random reaction time maybe 1.5 ds (coincidentally this is the average gamer reaction time), however non-random reaction times can be much faster (e.g. on a beat).
So if you wanted to go that fast, you could, the invokation should have relatively stable speeds (order of some milliseconds...
The issue is if you accept the wrong command instead of retyping it correctly, you never get the correctly spelled command into your history — and even worse, you don't get it to be more recent than the mistyped command.
Well to put it into context, I use fish shell, which will only save commands that have an exit code of 0. By using git autocorrect, I have guaranteed that all git commands have an exit code of 0 :)
Deciseconds is such an oddball choice of units. Better to specify the delay in either milliseconds or seconds - either are far more commonly used in computing.
I got really confused for a moment, thinking that "deciseconds" was some git-unit meaning "seconds needed to make a decision", like in "decision-seconds" xD
Note: english is not my mother tongue, but I am from the civilised part of the world that uses the metric system FWIW.
It's a decent, if uncommon, unit for human reactions. The difference between 0 and 1 seconds is a noticeably long time to wait for something, but the difference between n and n+1 milliseconds is too fine to be useful.
Milliseconds are a commonly-used unit. It doesn't really matter if 1 ms is too fine a granularity -- you'll just have to write "autocorrect = 500" in your config file instead of "autocorrect = 5", but who cares?
Back in the 70s, Hal Finney was writing a BASIC interpreter to fit in 2K of ROM on the Mattel Intellivision system. This meant every byte was precious. To report a syntax error, he shortened the message for all errors to:
I still laugh about that. He was quite proud of it.I feel like that would also make a good response from the text parser in an old-school interactive fiction game.
Slightly related, but I remember some older variants of BASIC using "?" to represent the PRINT statement - though I think it was less about memory and more just to save time for the programmer typing in the REPL.
All this being on a C64 of course, but I suspect most versions of Bill Gates's BASIC did something similar.
The story goes that ed was designed for running over a slow remote connection where output was printed on paper, and the keyboard required very firm presses to generate a signal. Whether this is true or folklore, it would explain a lot.
GNU Ed actually has optional error messages for humans, because why not.
(On certain architectures, you could use 1-byte soft-interrupt opcodes to call the most used subroutine, but 8080 lacked it IIRC; on 6502 you could theoretically use BRK for that. But likely you had other uses for it than printing error diagnostics.)
https://en.wikipedia.org/wiki/JOSS#/media/File:JOSS_Session....
https://en.wikipedia.org/wiki/JOSS
They had about 5KB of memory but comparing to the Intellivision the machine weighed about 5,000lbs.
There was once a contest between Caltech and MIT. Each was to write a program to play Gomoku, and they'd play against each other. Hal wrote a Gomoku-playing program in a weekend, and it trashed MIT's program.
It was never dull with Hal around.
Add another seven Easter eggs, and people could love that byte.
<https://www.gnu.org/fun/jokes/ed-msg.html>
RIP.
If the original setting had been named something bool-y like `help.autocorrect_enabled`, then the request to accept an int (deciseconds) would've made no sense. Another setting `help.autocorrect_accept_after_dsec` would've been required. And `dsec` is so oddball that anyone who uses it would've had to look up.
I insist on this all the time in code reviews. Variables must have units in their names if there's any ambiguity. For example, `int timeout` becomes `int timeout_msec`.
This is 100x more important when naming settings, because they're part of your public interface and you can't ever change them.
Same here. I'm still torn when this gets pushed into the type system, but my general rule of thumb in C++ context is:
is OK, because that's a function signature and you'll see the type when you're looking at it, but with variables, `timeout` is not OK, as 99% of the time you'll see it used like: Common use of `auto` in C++ makes it a PITA to trace down exact type when it matters.(Yes, I use IDE or a language-server-enabled editor when working with C++, and no, I don't have time to stop every 5 seconds to hover my mouse over random symbols to reveal their types.)
You cannot compile FooBar(5000), so there is never confusion in C++ like C has. You have to do explicit "FooBar(std::chrono::milliseconds(500))" or "FooBar(500ms)" if you have literals enabled. And this will handle conversion if needed - you can always do FooBar(500ms) and it will work even if actual type in microseconds.
Similarly, your "auto" example will only compile if gl_timeout is a compatible type, so you don't have to worry about units at all when all your intervals are using std::chrono.
I feel like Go strikes a good balance here with the time.Duration type, which I use wherever I can (my _msec example came from C). Go doesn’t allow implicit conversion between types defined with a typedef, so your code ends up being very explicit about what’s going on.
JetBrains does a great thing where they show types for a lot of things as labels all the time instead of having to hover over all the things.
Then you end up with something where you can write "TimoutSec=60" as well as "TimeoutSec=1min" in the case of systemd :)
I'd argue they'd been better of not putting the unit there. But yes, aside from that particular weirdness I fully agree.
But that's wrong too! If TimeoutSec is an integer, then don't accept "1min". If it's some sort of duration type, then don't call it TimeoutSec -- call it Timeout, and don't accept the value "60".
The best alternative I've found is to accept units in the values, "5 seconds" or "5s". Then just "1" is an incorrect value.
[1] https://www.joelonsoftware.com/2005/05/11/making-wrong-code-...
Personally I flag any such use of int in code reviews, and instead recommend using value classes to properly convey the unit (think Second(2) or Millisecond(2000)).
This of course depends on the language, it's capabilities and norms.
I suppose this is the "actual" problem with the git setting, in so far as there is an "actual" problem: the variable started out as a boolean, but then quietly turned into a timespan type without triggering warnings on user configs that got reinterpreted as an effect of that.
In fact, our French keyboards do have a "µ" key (as far as I remember, it was done so as to be able to easily write all SI prefixes) but using non-ASCII symbols is always a bit risky.
xmobar uses deciseconds in a similar, albeit more problematic place - to declare how often to refresh each section. Using deciseconds is fantastic if your goal is for example configs to have numbers small enough that they clearly can't be milliseconds, resulting in people making the reasonable assumption that it must thus be seconds, and running their commands 10 times as often as they intended to. I've seen a number of accidental load spikes originating from this issue.
EDIT: 1) is the result of my misreading of the article, the "previous value" never existed in git.
1) Pushing a change that silently break by reinterpreting a previous configuration value (1=true) as a different value (1=0.100ms confirmation delay) should pretty much always be avoided. Obviously you'd want to clear old values if they existed (maybe this did happen? it's unclear to me), but you also probably want to rename the configuration label..
2) Having `help.autocorrect`'s configuration argument be a time, measured in a non-standard (for most users) unit, is just plainly bad. Give me a boolean to enable, and a decimal to control the confirmation time.
The mistake was here. Instead of retargeting the existing setting for a different meaning, they should have added a new setting.
There are similar mistakes in other systems, e.g., MySQL has which can be 0 if disabled, 1 if enabled, and 2 was added as something special.So if you wanted to go that fast, you could, the invokation should have relatively stable speeds (order of some milliseconds...
1. it does not distinguish between dangerous and safe actions
2. it pollutes my shell history with mistyped commands
Reading this article gave me just enough of a nudge to just disable it after a year.
Note: english is not my mother tongue, but I am from the civilised part of the world that uses the metric system FWIW.