Testing the quickest way to retrieve the macOS name (Sonoma, etc.)

Your "guess" was astounding. In a million years I never would have guessed that a "string comparison" was actually a "numerically sensitive sorting algorithm." Had I know that, I would very likely have used your approach. The documentation is wrong and you knew that and you took advantage of that fact to solve the problem.

I would do whatever is simplest to write, understand and maintain. The "meat" of my solution is a single shell command, grep "^$KMVAR_LocalVersion". It's hard to get simpler than that.

Amazingly, there's actual Apple documentation about this, at least at the Finder level:

Filename Sorting Rules


The Finder’s sort order for file and directory names is based on the Unicode Collation Algorithm (Technical Standard UTS #10) defined by the Unicode Consortium. That standard provides a complete and unambiguous sort ordering for all Unicode characters and is available on the Unicode Consortium website (http://www.unicode.org). The Finder alters the default sorting behavior of this algorithm slightly by taking advantage of some sanctioned alternatives, specifically:

  • Punctuation and symbols are significant for sorting.
  • Substrings of digits are sorted according to their numeric value, as opposed to sorting the actual characters in the number.
  • Case is not considered during sorting.

It seems Keyboard Maestro uses the macOS method of file sorting, which makes sense.

If my memory is correct, this change happened with the move from Mac OS 9 to Mac OS X Public Beta. Before Mac OS X, the Finder sorted strictly on characters, where anything with "1" would come before anything with "2".

If my memory is wrong, I'm sure some other long-termer will correct me :slight_smile:.

-rob.

It's a guess about how it works. Finding out in the first place was probably a serendipitous mistake when trying to do something else!

Spoken like a true programmer :wink:

To be fair, the docs do say it is "alphabetically before/after" -- and, even though number order is undefined, I think that many people in a "non-programming" situation would consider that 2 comes before 11 just as aardvark comes before Ant.

Unfortunately the Filter action's "Sort Lines" appears to use ASCII ordering, where the opposite would be true, so you'll have to roll your own routine if you want the same "natural" behaviour when sorting lines of text.

I agree with you that that's what KM actually does. Indeed, I was the one that identified this and explained in this thread that the condition does that, as opposed to what the KM documentation says. Here's the KM documentation:

The Text condition evaluates a text token string and then checks if it:

  • is empty.
  • is not empty.
  • is exactly (case insensitively) a specified string.
  • is not exactly (case insensitively) a specified string.
  • contains (case insensitively) a specified string.
  • does not contain (case insensitively) a specified string.
  • starts with (case insensitively) a specified string. (v8+)
  • ends with (case insensitively) a specified string. (v8+)
  • is alphabetically before a specified string. (v7.2+) <-------------------- HERE

Not only does it make no mention whatsoever that this is not an alphabetical sort, but further down on the page it contrasts with a numerical sort:

  • is alphabetically after a specified string. (v7.2+)
  • matches a specified regular expression.
  • does not match a specified regular expression.
  • is numerically less than a specified calculation. (v8+) <-------------- HERE

Why would any objective reader of this documentation think that an "alphabetical sort" does numerical string comparisons when there's a numerical string comparison condition just four lines down the page?

Sorry, I wasn't meaning to imply anything about your post (or anyone's!), was just providing some historical context about the OS itself and its own issues with sorting.

I should have been clearer, but for an excuse, I had to drive to the airport at 4am, so I'll use that :).

-rob.

1 Like

Because that's not a numerical string comparison, just a numerical one. When you choose that or the following options the edit box changes to a calculation field.

The documentation may not be complete, in that it doesn't define "alphabetically" -- but it isn't wrong.

Numbers are stored as strings, not integers. So indeed it is a string comparison interpreting the string as a number. I.e, a numerical string comparison.

You can't determine how numbers are represented, or evaluated, at execution time based on how they are stored. And, given that KM very helpfully casts to the best "class" as required by context, it doesn't really matter.

If you are going to argue that, during execution, this:

is storing binary 00110001 in memory and not 00000001, I'd love to see the evidence.

Remember that in your example above you are explicitly comparing text. Whatever routine KM is using for that appears to follow Apple's "Finder rules" for string comparison, with the rules @griffman referenced. That has no bearing on how KM treats explicit numbers, such as the results of a calculation or function evaluation.

Yes, that's 100% exactly what I'm saying. However when you say "in memory" I'm interpreting that as the memory storage area for the KM variable itself, not as any temporary Engine work area used to evaluate expressions. Let me explain that in more details. For example, in this action:

... the string "1+2" is analyzed by the KM Engine, which converts the string "1" in an IEEE 754 double precision temporary storage location, and does the same thing for the string "2", then uses a real number add operation to add the two values, then converts the resulting IEEE 754 value back into a string which is where MyVar stores the string value "3".

Read the following page which says "all variables are just strings." That means all variables, including any variable containing "numbers" such as you provided above.

https://wiki.keyboardmaestro.com/manual/Variables

There are also posts on this website where The Architect explains this. At this moment I'm unable to find them.

The only time a numeric variable is NOT stored as a string is when the Engine is converting these strings to IEEE 754 double precision values. This is temporary, probably just for a millisecond, and is not ever how any variables "store" their numbers, including in the example you gave.

By the way, the value "1" when stored in IEEE 754 doesn't look anything like "00000001" it looks like this: "3f800000". You can check that yourself here at this conversion website:

https://www.h-schmidt.net/FloatConverter/IEEE754.html

That paragraph is a sub-section of "Variables in Text Fields" -- it's setting the stage for pseudo arrays. I'm not saying you're wrong, just that we need to consider the context of that statement.

But you may well be right -- I struggling to find something to prove otherwise and which doesn't have precision/casting problems, as illustrated by:

Deep waters -- and thank you, @Airy, for making me swim in them!

There is more information in this thread, including explanations from The Architect.

I think I was wrong on one point. The KM Engine uses both double precision floating point and 64-bit integer formats for some calculations in the Engine. I'm not sure how to determine the occasions that it chooses each format. Most likely it sticks to the 64-bit Integer format unless the string is over 15 digits or contains a decimal point.

Your snapshot above shows 7 digits of precision failing to give the correct result. I'm not sure how that could be, since the KM Engine doesn't use Single precision floating point.

Thanks, @Airy.

Peter's first post in that thread also states that KM "uses double to store values internally" -- so I guess the question is "at what point do they become 'internal', and for how long?".

Which is why I'm starting to doubt my own sanity :wink: But it's reproducible, even within a calculation (so probably not a string->number conversion issue):

At which point I have to assume problems at my end -- or problems with me!

I infer that this means for doing calculations. As I said earlier, I believe that this is for calculations only, not permanent storage.

If Peter doesn't want to reveal the details, that's okay. What we need to know is how to use KM, not how it works internally, which can change from time to time anyway.

Your second example confirms your first example, which is that the precision the KM engine can deal with before converting to real numbers is equivalent to single precision float values.

Keyboard Maestro uses doubles when doing numerical calculations.

doubles are not stored permanently, since variables are strings. So any result is converted to a string to store it in a variable.

There is a degree of rounding to ensure that you don't get bad results for normal operations (like 10/5 giving 1.9999999999999 for example).

Thanks, Peter. And to @Airy for making me question my assumptions.

I tip my hat to @Airy, withdraw all my incorrect statements from the above, and retire to ponder...