{
    "version": "https:\/\/jsonfeed.org\/version\/1",
    "title": "The ZAZ",
    "home_page_url": "https:\/\/thezaz.com\/",
    "feed_url": "https:\/\/thezaz.com\/blog\/json.php",
    "icon": "https:\/\/thezaz.com\/gfx\/giant_logo.png",
    "favicon": "https:\/\/thezaz.com\/gfx\/favicon120.png",
    "author": {
        "name": "Thom McGrath",
        "url": "https:\/\/twitter.com\/tekcor",
        "avatar": "https:\/\/secure.gravatar.com\/avatar\/0213452f7a795f1ccb2bfc27bbde2620?d=identicon&s=512"
    },
    "items": [
        {
            "id": "c34d7cb5-01cd-4561-b339-4f021d733fc4",
            "url": "https:\/\/thezaz.com\/blog\/navigating_the_perils_of_preem",
            "title": "Navigating the Perils of Preemptive Threads and Locking",
            "content_html": "<p>Since they launched last year, I've spent a lot of time with Xojo preemptive threads, both with brand new apps built from scratch for preemptive threading and with existing apps retrofitted for preemptive threading. They are a double-edged sword that gives you incredible power but also incredible danger.<\/p>\n<p>The greatest threat is deadlocking your code, which occurs when two or more threads wait for a lock that will never be released. I'll show you some common pitfalls and solutions, as well as a brilliant way to make your life easier and other potential problems to look out for.<\/p>\n<h2>The Locking Problem<\/h2>\n<p>Using either CriticalSection or Semaphore to lock parts of your code is a critical part of implementing preemptive threading. Locks work like bouncers who control how many people can enter a building at once. You define how many people the bouncer allows in at once. A CriticalSection allows one person at a time, while a Semaphore allows a specified number of people. When someone leaves, the bouncer lets the next person in.<\/p>\n<p>The problem arises when someone sneaks out the bathroom window. The bouncer won't know that someone left and will prevent someone else from taking their place forever. In your code, this is what happens when you accidentally leave a lock held.<\/p>\n<p>Consider the following code, where <code>mLock<\/code> is a <code>CriticalSection<\/code> defined in the same module as this method:<\/p>\n<pre class=\"code\"><code class=\"language-xojo\"><span class=\"xojo_code_text\">mLock.Enter\n\n<span class=\"xojo_code_keyword\">Var<\/span> Dict <span class=\"xojo_code_keyword\">As<\/span> Dictionary\nDict.Value(<span class=\"xojo_code_string\">&quot;One&quot;<\/span>) = <span class=\"xojo_code_integer\">1<\/span>\n\nmLock.Leave<\/span><\/code><\/pre>\n<p>Setting aside the fact that you don't need to lock a local variable, did you catch the problem? <code>Dict<\/code> was never initialized, so a <code>NilObjectException<\/code> will be raised before the lock can be released. If you're using an unhandled exception handler to keep your code running, there's now a problem because another thread can never enter that lock. This is a locking imbalance.<\/p>\n<p>This is also a great example of why it's a bad idea to continue running after the <code>Application.UnhandledException<\/code> event has fired. It indicates that something unexpected has gone wrong and your code is now in an unpredictable state. It's a rule I often violate myself, but it's still a bad idea.<\/p>\n<h2>Defending Your Locks<\/h2>\n<p>The code could be improved using a try block.<\/p>\n<pre class=\"code\"><code class=\"language-xojo\"><span class=\"xojo_code_text\">mLock.Enter\n<span class=\"xojo_code_keyword\">Try<\/span>\n  <span class=\"xojo_code_keyword\">Var<\/span> Dict <span class=\"xojo_code_keyword\">As<\/span> Dictionary\n  Dict.Value(<span class=\"xojo_code_string\">&quot;One&quot;<\/span>) = <span class=\"xojo_code_integer\">1<\/span>\n  mLock.Leave\n<span class=\"xojo_code_keyword\">Catch<\/span> Err <span class=\"xojo_code_keyword\">As<\/span> RuntimeException\n  mLock.Leave\n  <span class=\"xojo_code_keyword\">Raise<\/span> Err\n<span class=\"xojo_code_keyword\">End<\/span> <span class=\"xojo_code_keyword\">Try<\/span><\/span><\/code><\/pre>\n<p>This works, but I find it kind of ugly that I have to remember to unlock in both the try and catch sections. Instead, let's consider reporting the exception.<\/p>\n<pre class=\"code\"><code class=\"language-xojo\"><span class=\"xojo_code_text\">mLock.Enter\n<span class=\"xojo_code_keyword\">Try<\/span>\n  <span class=\"xojo_code_keyword\">Var<\/span> Dict <span class=\"xojo_code_keyword\">As<\/span> Dictionary\n  Dict.Value(<span class=\"xojo_code_string\">&quot;One&quot;<\/span>) = <span class=\"xojo_code_integer\">1<\/span>\n<span class=\"xojo_code_keyword\">Catch<\/span> Err <span class=\"xojo_code_keyword\">As<\/span> RuntimeException\n  App.ReportException(Err)\n<span class=\"xojo_code_keyword\">End<\/span> <span class=\"xojo_code_keyword\">Try<\/span>\nmLock.Leave<\/span><\/code><\/pre>\n<p>This certainly looks nicer, but it introduces a new problem: EndException and ThreadEndException. These are triggered when your app tries to quit or terminate a thread. You should not catch them. Okay, so let's update the code accordingly.<\/p>\n<pre class=\"code\"><code class=\"language-xojo\"><span class=\"xojo_code_text\">mLock.Enter\n<span class=\"xojo_code_keyword\">Try<\/span>\n  <span class=\"xojo_code_keyword\">Var<\/span> Dict <span class=\"xojo_code_keyword\">As<\/span> Dictionary\n  Dict.Value(<span class=\"xojo_code_string\">&quot;One&quot;<\/span>) = <span class=\"xojo_code_integer\">1<\/span>\n<span class=\"xojo_code_keyword\">Catch<\/span> Err <span class=\"xojo_code_keyword\">As<\/span> RuntimeException\n  <span class=\"xojo_code_keyword\">If<\/span> Err <span class=\"xojo_code_keyword\">IsA<\/span> EndException <span class=\"xojo_code_keyword\">Or<\/span> Err <span class=\"xojo_code_keyword\">IsA<\/span> ThreadEndException <span class=\"xojo_code_keyword\">Then<\/span>\n    mLock.Leave\n    <span class=\"xojo_code_keyword\">Raise<\/span> Err\n  <span class=\"xojo_code_keyword\">End<\/span> <span class=\"xojo_code_keyword\">If<\/span>\n  App.ReportException(Err)\n<span class=\"xojo_code_keyword\">End<\/span> <span class=\"xojo_code_keyword\">Try<\/span>\nmLock.Leave<\/span><\/code><\/pre>\n<p>While this is technically sufficient, it requires writing and maintaining a lot of boilerplate code every time you need to obtain a lock.<\/p>\n<h2>The Brilliant Solution<\/h2>\n<p><a href=\"https:\/\/github.com\/ktekinay\/Xojo-ThreadPool\/blob\/develop\/Common\/M_ThreadPool\/LockHolder.xojo_code\">Kem Tekinay's LockHolder class<\/a> will make your life so much easier, that it really should be something built into Xojo.<\/p>\n<p>It works by passing a lock object to a new instance of this class. When the class goes out of scope, the destructor fires and releases the lock. Therefore, it doesn't matter if an exception is thrown; your lock will be released. Our example code could then be written as follows:<\/p>\n<pre class=\"code\"><code class=\"language-xojo\"><span class=\"xojo_code_text\"><span class=\"xojo_code_keyword\">Var<\/span> Holder <span class=\"xojo_code_keyword\">As<\/span> <span class=\"xojo_code_keyword\">New<\/span> LockHolder(mLock)\n<span class=\"xojo_code_keyword\">Var<\/span> Dict <span class=\"xojo_code_keyword\">As<\/span> Dictionary\nDict.Value(<span class=\"xojo_code_string\">&quot;One&quot;<\/span>) = <span class=\"xojo_code_integer\">1<\/span><\/span><\/code><\/pre>\n<p>That's it! If you need to unlock it during execution, simply set the variable to nil. This makes lock balancing <strong>nearly<\/strong> foolproof.<\/p>\n<h2>Only Nearly Foolproof?<\/h2>\n<p>There are still ways your code can get into trouble. Polling and explicit yields, in both your code and plugin code, are especially dangerous.<\/p>\n<h3>Bad Practice Traps<\/h3>\n<p>For example, consider this code that waits for a socket to send data before closing.<\/p>\n<pre class=\"code\"><code class=\"language-xojo\"><span class=\"xojo_code_text\"><span class=\"xojo_code_keyword\">Var<\/span> Holder <span class=\"xojo_code_keyword\">As<\/span> <span class=\"xojo_code_keyword\">New<\/span> LockHolder(mLock)\n<span class=\"xojo_code_comment\">\/\/ Do some work<\/span>\n<span class=\"xojo_code_keyword\">While<\/span> Socket.BytesLeftToSend &gt; <span class=\"xojo_code_integer\">0<\/span>\n  Socket.Poll()\n  Thread.SleepCurrent(<span class=\"xojo_code_integer\">10<\/span>)\n<span class=\"xojo_code_keyword\">Wend<\/span><\/span><\/code><\/pre>\n<p>The <code>Thread.SleepCurrent<\/code> method will cause the current thread to sleep. <strong>However<\/strong>, if executed on the main thread, a new iteration of the main loop will start, creating the illusion of multitasking. This is essentially the same as the problematic <code>App.DoEvents<\/code>, and with preemptive threading, it can easily cause a deadlock. Even with cooperative threading, this code can cause a deadlock; it's just more difficult.<\/p>\n<p>For this particular example, you'll need to use the <code>SendComplete<\/code> event. Yes, this makes the code more difficult, but now you can see why a polling loop is considered a bad practice.<\/p>\n<h3>Good Practice Traps<\/h3>\n<p>Consider the following example of connecting to a database and inserting a record.<\/p>\n<pre class=\"code\"><code class=\"language-xojo\"><span class=\"xojo_code_text\"><span class=\"xojo_code_keyword\">Var<\/span> Connection <span class=\"xojo_code_keyword\">As<\/span> <span class=\"xojo_code_keyword\">New<\/span> PostgreSQLDatabase\nConnection.Host = <span class=\"xojo_code_string\">&quot;127.0.0.1&quot;<\/span>\nConnection.Port = <span class=\"xojo_code_integer\">5432<\/span>\nConnection.UserName = <span class=\"xojo_code_string\">&quot;thom&quot;<\/span>\nConnection.Password = <span class=\"xojo_code_string\">&quot;this isn&apos;t a real password&quot;<\/span>\nConnection.DatabaseName = <span class=\"xojo_code_string\">&quot;testing&quot;<\/span>\nConnection.Connect\n\nConnection.BeginTransaction\nConnection.ExecuteSQL(<span class=\"xojo_code_string\">&quot;INSERT INTO mytable (col1, col2) VALUES ($1, $2);&quot;<\/span>, <span class=\"xojo_code_string\">&quot;Value1&quot;<\/span>, <span class=\"xojo_code_string\">&quot;Value2&quot;<\/span>)\nConnection.CommitTransaction<\/span><\/code><\/pre>\n<p>Have you noticed how this code is dangerous? No, it's not because of the lack of an exception handler. I bet you haven't because, aside from the lack of error handling, this is a very respectable block of code.<\/p>\n<p>The problem stems from the <code>MultiThreaded<\/code> property, which is set to true by default. I didn't include it here to make it as obvious as it would be in real code. When this property is enabled, the database plugin yields during statements. As in the last example, this causes a new iteration of the main event loop to occur in the middle of your existing code. Have you ever seen a stack trace in which a timer's action appears mixed in with completely unrelated code? I have, and, as in the previous example, it's the equivalent of calling <code>App.DoEvents<\/code>.<\/p>\n<p>For preemptive threads, always disable any type of yielding. You don't need it. The <code>SQLiteDatabase<\/code> class has a <code>ThreadYieldInterval<\/code> property that should be set to 0 for preemptive threads. Fortunately, 0 is the default.<\/p>\n<h2>Conclusion<\/h2>\n<p>Preemptive threads are like the mythical Sirens. They'll tempt you with tales of amazing performance, and your initial tests will reinforce that temptation while lulling you into a false sense of security. Then, when you think you've got it figured out and launch it in production, they'll drown you. They'll exploit every flaw in your code, leaving you desperate for answers. There will be few of those. Due to the sunk cost fallacy, you'll spend countless hours trying to fix the problem.<\/p>\n<p>In other words, Xojo was right to avoid these for so long. If you don't absolutely <em>need<\/em> preemptive threads, don't use them. Use workers or multiple processes instead. Your sanity will thank you.<\/p>\n<p>That said, if you can tame them, they can give you incredible power.<\/p>",
            "date_published": "2025-11-02T05:08:18+00:00",
            "date_modified": "2025-11-02T05:08:07+00:00"
        },
        {
            "id": "bba8fad5-bef1-40ab-b51a-a8feeebfee8d",
            "url": "https:\/\/thezaz.com\/blog\/code_signing_for_xojo_apps_on",
            "title": "Code Signing for Xojo apps on Windows with a Yubikey",
            "content_html": "<p>As of June 1, 2023, the private keys required to perform Windows code signing <strong>must<\/strong> be stored on a FIPS-compliant device. In most cases, a Yubikey is the tool of choice. This solves some problems and creates others.<\/p>\n<p>In the past, when I ordered my certificates from K Software, as so many Xojo developers do, actually <em>getting<\/em> my private key was a huge challenge. K Software required the use of old browsers, and thanks to browser auto-updating, extracting the private key was problematic to say the least. So using my own private key is an absolute blessing. But the new frustration is that the private key now has to be locked on a Yubikey.<\/p>\n<h2>Buying a certificate<\/h2>\n<p>For my most recent renewal, I decided to go through ssl.com instead of K Software to get a much better price. At the time of this writing, a 1-year OV certificate from K Software is $313, and only $129 from ssl.com. At K Software's price, you might as well buy the EV certificate for $405 and get that sweet instant SmartScreen reputation. But ssl.com also allows you to buy up to 10 years, which drops the price to just $64.50 per year. This is the option I took, although it should be noted that they are only allowed to issue you one 3-year certificate at a time. When that expires, they will issue you a new one.<\/p>\n<p>K Software will sell you the Yubikey for $90. That's a very fair price, considering that one directly from Yubico costs $80-$90, depending on the model. On the other hand, ssl.com's price for a Yubikey is absolutely insane at $279. There's <em>some<\/em> value in getting the key from them if you want to avoid the attestation steps. But if you can follow instructions and use a command line, save yourself the $200 and buy directly from Yubico.<\/p>\n<h2>Setting up the Yubikey<\/h2>\n<p>Ok, so the certificate is purchased, the validation is done, the Yubikey is delivered, and now it's time to actually sign something. You need to perform steps called \"attestation\", and ssl.com's documentation for this is actually pretty good, so I won't repeat it here. Instead, I'll link to <a href=\"https:\/\/www.ssl.com\/how-to\/key-generation-and-attestation-with-yubikey\/\">their article on the subject<\/a>.<\/p>\n<p><strong>HOWEVER<\/strong> there are two pieces of information they left out.<\/p>\n<h3>Setup PIV<\/h3>\n<p>First, you'll need to set up your private key on your Yubikey <strong>before following the other instructions<\/strong>. In Yubikey Manager, go to the PIV section under Applications and press \"Configure PINs\" to begin the setup. If you've already done this for your Yubikey, skip to the next section. The PIN is something like a six-character code that you will use as a password for signing. It's generally something you'll want to remember. The PUK is an eight character code that can be used to unlock the device if the PIN has been entered incorrectly too many times. It doesn't have to be memorable, but it should be stored somewhere safe. The Management Key is a longer string that you'll need to generate. My advice is to use a quick Xojo app:<\/p>\n<pre class=\"code\"><code class=\"language-xojo\"><span class=\"xojo_code_text\"><span class=\"xojo_code_keyword\">Var<\/span> Board <span class=\"xojo_code_keyword\">As<\/span> <span class=\"xojo_code_keyword\">New<\/span> Clipboard\nBoard.Text = EncodeHex(Crypto.GenerateRandomBytes(<span class=\"xojo_code_integer\">32<\/span>))<\/span><\/code><\/pre>\n<p>Both the PUK and Management Key should be stored in a secure location, such as a reputable password manager.<\/p>\n<h3>Request a Code Signing Certificate<\/h3>\n<p>Second, in step 10 of their guide, they instruct you to go to the \"End Entity Certificates\" section to download the DER certificate to install on your Yubikey. They skipped a step. When you buy a certificate, they issue you an eSigner certificate so you have the privilege of paying for the overpriced eSigner service. This service would cost me about $175 per month. No one should use it.<\/p>\n<p>Instead, you will need to open a ticket or use their live chat to have them create an actual code signing certificate. In the End Entity Certificates, you should see both an \"eSigner Code Signing Certificate\" and a \"Code Signing Certificate\". Use the table in the section for the regular \"Code Signing Certificate\" section. Also, don't use the look-alike table at the top of your dashboard labeled \"Certificate Downloads\".<\/p>\n<p>Once you've completed the attestation steps, you're ready to try signing something. Code signing on Windows is most commonly done with <code>signtool<\/code>, and <a href=\"https:\/\/support.yubico.com\/hc\/en-us\/articles\/360016614840-Code-Signing-with-the-YubiKey-on-Windows\">Yubico has instructions on how to use your Yubikey to sign a file with signtool<\/a>.<\/p>\n<p>These instructions work fine, and if you already have signtool installed, I recommend following them to get familiar. When you run the command, you'll get a prompt asking for your PIN, and once you enter it, your file will be signed. It's really not much different from how we used to sign before the Yubikey requirement.<\/p>\n<h2>Signing without the PIN<\/h2>\n<blockquote>\n<p>This section was updated in December 2024. The original instructions used osslsigncode but the signatures produced were not trusted by Windows. These updated instructions are easier and produce trusted signatures.<\/p>\n<\/blockquote>\n<p>The problem is that your PIN is needed for every single file that needs to be signed. For an Inno Setup installer, the absolute minimum number of signatures required is 3: your application, the installer, and the uninstaller. But realistically it will be more. And if you have multiple installers like I do - 32-bit, 64-bit, ARM, and combo - the number of times your PIN is needed can be very annoying.<\/p>\n<p>This is where <code>scsigntool<\/code> comes in handy. This is kind of like a wrapper around the official <code>signtool<\/code> process. You still need an official <code>signtool<\/code> executable. <code>scsigntool<\/code> will take your pin  on the command line and inject it into signtool's shared memory so you don't need to enter it for every file. To get <code>scsigntool<\/code> ready, follow these steps:<\/p>\n<ol>\n<li>Download the <a href=\"https:\/\/developer.microsoft.com\/en-us\/windows\/downloads\/windows-sdk\/\">Windows SDK<\/a> though you only need to install the \"Windows SDK Signing Tools for Desktop Apps\" component.<\/li>\n<li>Download <a href=\"https:\/\/www.mgtek.com\/smartcard\">SmartCard Tools<\/a>. Copy the zip archive's contents (3 files at the time of this writing) into the same directory as <code>signtool<\/code>. The default path is <code>C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.26100.0\\x64<\/code> but could change if a newer version is released by Microsoft.<\/li>\n<li>Download and install the <a href=\"https:\/\/www.yubico.com\/support\/download\/smart-card-drivers-tools\/\">YubiKey Smart Card Minidriver<\/a>.<\/li>\n<li>Obtain your certificate's thumbprint. The instructions can be found on <a href=\"https:\/\/support.yubico.com\/hc\/en-us\/articles\/360016614840-Code-Signing-with-the-YubiKey-on-Windows\">Yubico's website<\/a> but the high-level overview is to use <code>certmgr.msc<\/code> to find your certificate under Certificates - Current User -&gt; Personal -&gt; Certificates. Double click your certificate and you'll find the thumbprint in the Details tab.<\/li>\n<\/ol>\n<p>Now you're ready to configure Inno Setup to do the signing. Launch Inno Setup and open your installer script. In the Tools menu choose \"Configure Sign Tools\" to list available signing tools. If you've done signing with Inno Setup before, this list will have at least one entry that you could update. This tutorial will pretend there are no in the list.<\/p>\n<p>Press the \"Add\" button and the first dialog will ask for a name. You'll use this in the installer script to tell Inno Setup which tool to use. I named mine <code>The ZAZ<\/code> but you can name yours however you like. The same executable can be used more than once, so if you sign with multiple certificates, naming the tool like the certificate will help stay organized.<\/p>\n<p>The next window asks for the signing command. This is where you enter the command that would be executed on the command, with a few placeholders instead. My command looks like this:<\/p>\n<pre class=\"code\"><code class=\"language-plain\">\"C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.26100.0\\x64\\scsigntool.exe\" \/pin &lt;pin&gt; sign \/sha1 &lt;thumbprint&gt; \/tr http:\/\/timestamp.sectigo.com \/td sha384 \/fd sha384 $p<\/code><\/pre>\n<p>Replace <code>&lt;pin&gt;<\/code> and <code>&lt;thumbprint&gt;<\/code> with your Yubikey PIN and certificate thumbprint, respectively. The <code>\/pin<\/code> argument <strong>must<\/strong> come first. The other arguments tell <code>signtool<\/code> to include a timestamp and use more secure SHA-384 hashes instead of the default SHA-256. <code>$p<\/code> will be replaced by parameters from your install script. <strong>This command is not stored in your install script, so it is ok to include the PIN here even if your install script is checked into version control.<\/strong> Officially, the recommendation is not to store the PIN anywhere, but Microsoft hasn't given us better options to automated signing.<\/p>\n<p>In your install script, add to <code>[Setup]<\/code> a <code>SignTool<\/code> line:<\/p>\n<pre class=\"code\"><code class=\"language-plain\">SignTool=The ZAZ \/d $qApp Name$q \/du $qhttps:\/\/website.app$q $f<\/code><\/pre>\n<p>Everything after the tool name will be used instead of <code>$p<\/code> in the tool's command. These two arguments set the app name and website. <code>$q<\/code> will be replaced by quotation marks. By setting these two arguments in the install script, the same tool can be used for multiple products that should be signed by the same certificate. <code>$f<\/code> will be replaced by the full file path.<\/p>\n<p>Finally in your <code>[Files]<\/code> section add a <code>signonce<\/code> flag to any file (or group of files) that should be signed. This tells Inno Setup to execute your command with the necessary replacements so that it can sign the specified files.<\/p>\n<p>And that's pretty much it. You can use all the features of signtool without having to enter your PIN all the time.<\/p>",
            "date_published": "2024-05-17T04:41:29+00:00",
            "date_modified": "2024-12-28T07:49:21+00:00"
        },
        {
            "id": "f0ff3aaa-171a-4163-8df6-c6dad6b3cfd2",
            "url": "https:\/\/thezaz.com\/blog\/quick_tip_setting_reminders_in",
            "title": "Quick Tip: Setting reminders in your Xojo code",
            "content_html": "<p>If you're in the middle of refactoring and find something that needs to be done, but you're not quite ready to tackle it yet, here's a nice way to make sure you don't forget.<\/p>\n<pre class=\"code\"><code class=\"language-xojo\"><span class=\"xojo_code_text\"><span class=\"xojo_code_keyword\">#If<\/span> DebugBuild\n  <span class=\"xojo_code_keyword\">#Pragma<\/span> Warning <span class=\"xojo_code_string\">&quot;This isn&apos;t implemented yet&quot;<\/span>\n<span class=\"xojo_code_keyword\">#Else<\/span>\n  <span class=\"xojo_code_keyword\">#Pragma<\/span> Error <span class=\"xojo_code_string\">&quot;This isn&apos;t implemented yet&quot;<\/span>\n<span class=\"xojo_code_keyword\">#EndIf<\/span><\/span><\/code><\/pre>\n<p>You can of course add comments or anything else you need to help you remember. And the message can be anything you like. The point is this will show the message in Xojo's analyzer (which you <em>should<\/em> be using) but still allow you to run and debug the project. But if you try to build, you'll get stopped. This way you won't accidentally ship a build to your customers that has missing functionality.<\/p>",
            "date_published": "2021-10-17T17:48:25+00:00",
            "date_modified": "2021-10-17T17:48:22+00:00"
        },
        {
            "id": "350d9459-c1be-4178-a883-2a1213f77f32",
            "url": "https:\/\/thezaz.com\/blog\/setting_your_own_accent_color",
            "title": "Setting your own accent color for Xojo macOS apps",
            "content_html": "<p>As of Big Sur, applications can provide their own accent color for things like default buttons, focus rings, selection indicators, checkboxes, radio buttons, and so on. I personally really like this, as it allows Mac apps to have just a little more personality. Unfortunately, Xojo does not have a built-in option for this and most likely never will. This isn't because Xojo doesn't <em>want<\/em> there to be, but because doing so requires reverse engineering Apple's compiled asset catalog format.<\/p>\n<p>In this guide, I'll teach you how to set this up by first creating an asset catalog in Xcode, compiling that catalog, and utilizing it in your macOS app. I'll cover everything you need to know, step by step, even if you've never used Xcode, the command line, or any of Xojo's automation tools. This guide assumes Xcode is already installed however.<\/p>\n<h3>A brief introduction to asset catalogs<\/h3>\n<p>Developing apps for Apple devices these days typically includes something called an asset catalog. It can store color sets and image sets, similar to Xojo's ColorGroup and ImageSet classes. These catalogs can be manipulated by Apple during distribution. For example, downloading an iOS app on an iPhone Pro Max will automatically strip away the 1x and 2x resolutions of images that have a 3x resolution. By doing so, they allow Apple's app stores to deliver more optimized downloads.<\/p>\n<p>The good news is that asset catalogs are pretty simple. They are just folders full of images and json files. Xcode has an editor for them that you absolutely should use. The bad news is that the asset catalogs cannot be used as-is and require being compiled into a \"car\" file first. This is done with the <code>actool<\/code> command line tool, which is included with Xcode. For Xojo to allow custom accent colors, they would need to replicate this process. This is why the feature will likely never come to Xojo.<\/p>\n<h3>Creating your asset catalog<\/h3>\n<p>Launch Xcode, and from the File menu choose \"New -&gt; File\u2026\" or just press \u2318N. From the template chooser, find \"Asset Catalog\" under the \"Resource\" header. The filter field helps with this. You will immediately need to save this folder somewhere. I recommend keeping it near your project of course.<\/p>\n<p>Now you have an empty asset catalog. At the bottom of the left column, use the plus button to choose \"Color Set.\" A new row will be created ready for you to name it. I called mine <code>ThisIsTheAccentColor<\/code>. In the larger content area, you will have two white squares for \"Any Appearance\" and \"Dark\" with no obvious way to set the colors. From the View menu, choose \"Inspectors -&gt; Attributes\" or \u2325\u23184. In the newly-opened attributes inspector you'll see an Appearances menu on the right. The default of \"Any, Dark\" is what I recommend because nearly every color needs some sort of adjustment for dark mode, even branding colors. In this context, \"Any\" means anything that is not dark mode. That would include light mode, and any future modes that Apple may or may not introduce. You can choose \"Any, Light, Dark\" instead, to supply an explicit light mode code, but considering we don't know what other options might be added, there's little purpose in doing so.<\/p>\n<p>Clicking one of the squares adds the \"Color\" section to the attributes inspector, which will default to sRGB content. That's good. Use the options to set your color. Repeat as necessary for each square to complete the color set.<\/p>\n<p><img src=\"https:\/\/thezaz.com\/blog\/setting_your_own_accent_color\/accents_asset_catalog.png\" class=\"inline-img\" alt=\"Look, I never said this was a tutorial about picking good colors.\" \/><\/p>\n<p>At this point, you're done with the asset catalog itself, though there are some more neat things that can be done with it in the future. The asset catalog is how you would activate Big Sur's system-generated document icons, for example. But for now, we've done everything we need to.<\/p>\n<h3>Creating an Info.plist file<\/h3>\n<p>Every app for every Apple device has an <code>Info.plist<\/code> file inside of it. Xojo will generate it for you, but you need to add a new value to it that Xojo does not support. If you already know how to do this, you need to add <code>NSAppAccentColorName<\/code> as a string set to the name of your color set. Mine will be set to <code>ThisIsTheAccentColor<\/code>. Skip to the next section if you're comfortable doing this, or read on if you're not.<\/p>\n<p>Still in Xcode, you need another new file. Again, choose \"New -&gt; File\u2026\" from the File menu. This time in the template chooser, you need to select \"Property List\" from the \"Resource\" header. Like before, you need to save it immediately, however this time it <strong>must<\/strong> be named <code>Info.plist<\/code>. Save it near your project like you did the asset catalog. In the first row below the header, you'll see \"Information Property List.\" Hover your cursor in that row along the right edge of the column until a plus button appears. Tap it once, and a menu of choices will appear. For some reason, the one we need is not in this menu. So instead, type <code>NSAppAccentColorName<\/code>. In the \"Type\" column, make sure the type is \"String.\" If it isn't, clicking the type will open a menu allowing you to change it. Lastly, in the \"Value\" column enter the name of your color set from the asset catalog. Remember I named mine <code>ThisIsTheAccentColor<\/code> so that's what I'll enter here. Save your <code>Info.plist<\/code> and you can exit Xcode if you like.<\/p>\n<p><img src=\"https:\/\/thezaz.com\/blog\/setting_your_own_accent_color\/accents_info_plist.png\" class=\"inline-img\" alt=\"The Info.plist does not need much.\" \/><\/p>\n<h3>Compiling your asset catalog<\/h3>\n<p>Next up, we'll need to compile the asset catalog. This is done using the command line. I'll walk you through it as best as I can assuming you have no experience with it. Launch Terminal and type <code>actool --compile ~\/Desktop --platform macosx --minimum-deployment-target 10.11<\/code>, but do <strong>not<\/strong> press return. Make sure what was typed ends in a single space, because web browsers tend to trim it off the end. Next find your asset catalog and drag it into your Terminal window. This will add the full path to the end of the command and will look something like <code>actool --compile ~\/Desktop --platform macosx --minimum-deployment-target 10.11 \/Users\/thommcgrath\/Desktop\/Accent\\ Color\\ Sample\/Media.xcassets<\/code>. Press return to begin the work, which will take a couple seconds. When it completes, you'll see some XML output. It will have put an <code>Assets.car<\/code> folder on your desktop. Move this near your project, but do not rename it. You're done with Terminal.<\/p>\n<p>For those more experience with the command line, you can of course change the destination using the <code>--compile<\/code> parameter.<\/p>\n<p><img src=\"https:\/\/thezaz.com\/blog\/setting_your_own_accent_color\/accents_terminal.png\" class=\"inline-img\" alt=\"The terminal after compiling the accent catalog.\" \/><\/p>\n<h3>Adding the files to your Xojo project<\/h3>\n<p>If you already know how to use build automation, you'll need to have your <code>Assets.car<\/code> file added to your app's resources folder. If you don't know how to use build automation, follow the steps in the next paragraph.<\/p>\n<p>In your Xojo project, use the Insert menu to choose \"Build Step -&gt; Copy Files.\" Name this object as descriptive as possible. Something like <code>CopyResourcesMac<\/code> would be good, in case you need one for Windows and Linux in the future. In the inspector, set the Destination to \"Resources Folder\" and then drag your <code>Assets.car<\/code> file into the middle list. Then drag this build step into the \"macOS\" checkbox below \"Build Settings\" in Xojo's navigator. The navigator will gain a \"Build\" item as a child of \"macOS\" and your build step will be listed just before it. You need to move your build step after that \"Build\" item. Most build steps should be triggered after the build itself, but some can be placed before it if the step were to change the project prior to building.<\/p>\n<p>Finally, add your <code>Info.plist<\/code> file to your project. Just drag it right into the navigator. Xojo will include its keys during the build process.<\/p>\n<p><img src=\"https:\/\/thezaz.com\/blog\/setting_your_own_accent_color\/accents_xojo_project.png\" class=\"inline-img\" alt=\"A Xojo project with everything it needs for showing custom accent colors.\" \/><\/p>\n<h3>Test it out<\/h3>\n<p>That's it, you're done. Run your application and your buttons will have the new color. If they do not, check your System Preferences. Under General, make sure the accent color is set to \"Multicolor\" so that apps may pick their own. The colors should immediately change in your app.<\/p>\n<p>And here's some screenshots of the hideous colors I chose:<\/p>\n<p><img src=\"https:\/\/thezaz.com\/blog\/setting_your_own_accent_color\/accents_light_mode.png\" class=\"inline-img\" alt=\"Yeah, who doesn&#039;t love hot pink?\" \/>\n<img src=\"https:\/\/thezaz.com\/blog\/setting_your_own_accent_color\/accents_dark_mode.png\" class=\"inline-img\" alt=\"Cyan is at least a little more tolerable.\" \/><\/p>",
            "date_published": "2021-09-25T18:52:33+00:00",
            "date_modified": "2021-09-25T18:52:29+00:00",
            "attachments": [
                {
                    "url": "https:\/\/thezaz.com\/blog\/setting_your_own_accent_color\/AccentColorSample.zip",
                    "mime_type": "application\/zip",
                    "title": "AccentColorSample.zip",
                    "size_in_bytes": "9818"
                },
                {
                    "url": "https:\/\/thezaz.com\/blog\/setting_your_own_accent_color\/accents_asset_catalog.png",
                    "mime_type": "image\/png",
                    "title": "accents_asset_catalog.png",
                    "size_in_bytes": "528456"
                },
                {
                    "url": "https:\/\/thezaz.com\/blog\/setting_your_own_accent_color\/accents_info_plist.png",
                    "mime_type": "image\/png",
                    "title": "accents_info_plist.png",
                    "size_in_bytes": "254648"
                },
                {
                    "url": "https:\/\/thezaz.com\/blog\/setting_your_own_accent_color\/accents_terminal.png",
                    "mime_type": "image\/png",
                    "title": "accents_terminal.png",
                    "size_in_bytes": "438446"
                },
                {
                    "url": "https:\/\/thezaz.com\/blog\/setting_your_own_accent_color\/accents_xojo_project.png",
                    "mime_type": "image\/png",
                    "title": "accents_xojo_project.png",
                    "size_in_bytes": "696751"
                },
                {
                    "url": "https:\/\/thezaz.com\/blog\/setting_your_own_accent_color\/accents_light_mode.png",
                    "mime_type": "image\/png",
                    "title": "accents_light_mode.png",
                    "size_in_bytes": "255297"
                },
                {
                    "url": "https:\/\/thezaz.com\/blog\/setting_your_own_accent_color\/accents_dark_mode.png",
                    "mime_type": "image\/png",
                    "title": "accents_dark_mode.png",
                    "size_in_bytes": "269161"
                }
            ]
        },
        {
            "id": "f7e2eda5-2b1e-43c4-a8c0-9619f317806f",
            "url": "https:\/\/thezaz.com\/blog\/its_time_to_turn_this_ship_aro",
            "title": "It's Time to Turn This Ship Around",
            "content_html": "<p>For a tool that has been with me for more than half my life, generates 100% of my income, and I've poured five years of my life into developing... I give Xojo a hard time. I realized over on the \"Xojo Blogs and Resources\" page of ifnotnil.com that my blog includes an \"often critical\" component to its description. It's not wrong, but that needs to change. When was the last time I wrote something trying to help developers do their jobs? I had a spat of tutorials a year ago, but before that my last tutorial was December 2013.<\/p>\n<p>I don't mind being critical of Xojo. I do mind when it's all I do on this site. That'll change.<\/p>",
            "date_published": "2021-06-30T20:51:52+00:00",
            "date_modified": "2021-06-30T20:51:49+00:00"
        },
        {
            "id": "46175c48-5f53-4f48-a0e8-c864bd1946e2",
            "url": "https:\/\/thezaz.com\/blog\/xojos_user_confidence_problem",
            "title": "Xojo's User Confidence Problem",
            "content_html": "<p>The recent <a href=\"https:\/\/forum.xojo.com\/t\/xojo-is-technical-dept\/64138\">Xojo is technical debt<\/a> discussion on the Xojo forum has sparked some thoughts in my mind. This isn't really about that discussion though, otherwise I'd keep all my thoughts there. But some of the comments about Xojo's quality has me wanting to write about my experiences both inside and outside the company. Many blame the rapid release model for Xojo's perpetual beta status, but I don't think it's that simple. In fact, I think the rapid release model is a symptom, not the cause.<\/p>\n<p>In most projects there exists at least two branches of development. Though their names may vary, at the high level they are the stable and dev branches. Bug fixes are typically made to stable and merged into dev, while features are made into dev and merged into stable only when it's time for a new feature version. Stable versions can be released with great frequency, giving more time for the next feature version to become ready for release. In very well organized projects, every feature is given its own branch and merged into a feature release only when appropriate.<\/p>\n<p>Xojo doesn't really operate this way. There are still two branches of development, but they only overlap during the testing period. Once a release is declared finished, all work - both bug fixes and features - are made to the same branch. This is because Xojo doesn't <em>want<\/em> to make point releases. They do it only in exceptional cases.<\/p>\n<p>As I mentioned earlier, the rapid release model is a symptom. The cause is Xojo's desire to have their cake and eat it to. Their pricing model wants to be a subscription. Subscription software is very desirable for revenue because even if you don't make more money, you can make consistent money. With my own Beacon app, I could probably make at least twice as much money selling it as a subscription. I don't because I hate subscription software. And therein lies the problem: people dislike subscription software. So the rapid release model was introduced to get close to a subscription without actually <em>being<\/em> a subscription. They want to sell you a year of updates and in order for you do not feel cheated by that, they promise a certain number of feature releases per year.<\/p>\n<p>That's not a bad thing in and of itself. Such a model could work, and one could argue it is working, as Xojo has been doing this for years now and they are still in business. But the fact that customers complain about this model is maybe an indication that something could be improved.<\/p>\n<p>The heart of the problem is that we get 3-4 feature releases per year, and very few bug fix releases. I'd like to see more bug releases. At one point the team talked about being able to deliver framework fixes weekly. That might be a bit extreme, but a new build of fixes every other week would be remarkable. Then every 3 months (or so) we'd get a feature release. Heck, I'd be happy with feature releases every 6 months.<\/p>\n<p>While working at Xojo counter arguments about quality with the fact that each release sees hundreds of bug fixes. That's true, but it also brings with it additional changes which make developers uneasy about updating their Xojo version for existing projects. As the saying goes, the devil you know is better than the devil you don't. Developers would rather work with the bugs they are aware of than risk discovering new bugs, which Xojo has a habit of introducing each release. And since releases don't happen for months, we have to suffer those bugs for a long time, if they even get fixed for the next release.<\/p>\n<p>That's why more frequent bug fix releases would do wonders for the community. If I update my IDE mid project and discover a bug, when a bug fix release is only a couple weeks away, I can probably wait it out. There's no guarantee the next bug fix release will include the fix, but it could. I'd still rather wait 4 or 6 weeks for a fix than the minimum of 12 we wait now.<\/p>\n<p>Every developer knows that feature releases have the most bugs. Mine do. It's very normal for the \".0\" releases of anything to be the most buggy. But most developers correct that pretty quickly with bug fix releases shortly after the feature release. Xojo does not, and <em>that<\/em> is where the customer confidence problem comes from.<\/p>\n<p>If Xojo wants to shake this \"fix one thing, break two more\" reputation, they need to actually release rapidly. I sure as hell wouldn't be successful only making 4 releases per year, and my app is much simpler than Xojo.<\/p>",
            "date_published": "2021-06-28T19:47:04+00:00",
            "date_modified": "2021-06-28T19:45:37+00:00"
        },
        {
            "id": "e7a1bb1a-cfac-45cc-8c43-5e34078df219",
            "url": "https:\/\/thezaz.com\/blog\/a_story_of_homeownership_and_t",
            "title": "A story of homeownership and things only exciting to adults",
            "content_html": "<p>When we bought our second car, we managed to clean out the second bay of the garage to begin parking it inside with the other. But the garage door opener from 1979 just couldn\u2019t accept a remote. I couldn\u2019t find an option online, nor could an expert find any way to make it happen. In the winter, this was especially frustrating, as it meant my wife could not close the garage on her way out in the morning, letting all that nice cold air in.<\/p>\n<p>So I set out to have it replaced. After it took a friend and myself 12 hours to install my Ryobi opener about 4 years ago, this was a project I was confident I did not want to do myself. I also decided that I hated that Ryobi opener enough that I wanted it replaced too. I found an installer who estimated it would cost me about $300 to install both, so I ordered a couple Chamberlain openers and setup the appointment. I wanted the better Liftmaster models, but just couldn\u2019t justify the price. So this project was estimated at around $800 altogether.<\/p>\n<p>The day before the appointment, the guy who will be doing the work calls to find out what exactly I ordered so he can give me an accurate price. He tells me it would cost me $800 <strong>each<\/strong> to have them installed, because the Chamberlains come in a zillion pieces and they take much longer to install. I guess their dispatch assumed I was buying something from Liftmaster, which don\u2019t need to be packaged to fit onto store shelves. They come in larger pieces that are significantly faster to install. So my options were: cancel the appointment, install the Chamberlains for $2100 total project cost, or install Liftmasters for $1200 total project cost. Since I originally wanted the Liftmasters anyway, you can guess which option I chose.<\/p>\n<p>The guy comes out the next morning and starts to see what he\u2019s working with. And it\u2019s not good. All the equipment, aside from the Ryobi opener, is original from 1979 when the house was built. One of the tracks are bent, some of the rollers are busted, and even the springs are too weak. I think odds are they are too weak because they <em>were<\/em> replaced at some point, but I have no record of that. So he can continue with the installation, but he\u2019d have to void the warranty and couldn\u2019t promise the openers would even move the doors. Newer models are much more sensitive for safety, and might detect the extra weight as an obstruction. He could refurbish the hardware, but that means replacing the tracks, taking the doors down, etc. which takes a lot of time. To refurbish the doors and install new openers, would be $3200 total project cost. This project has grown in price significantly from the $800 originally expected.<\/p>\n<p>Alternatively, it would cost the same $3200 to have brand new insulated steel doors installed. That means new hardware, new openers, and new doors, which effectively takes refurbishing off the table. So I could cancel the project and live with the crummy door that we can\u2019t close remotely, install the openers that may not work and have no warranty, or spend a lot more for the only \u201cgood\u201d option.<\/p>\n<p>I chose to get the new doors. It took about a month to get the parts, and they were installed today. I\u2019ve already noticed some pretty astonishing differences.<\/p>\n<p>Traditionally, on a cold night like tonight, when the 800sqft living room above the garage turns the heat down at midnight, the ambient temp would drop from 67F to 58F in about 30-45 minutes. With the new doors, I\u2019m writing this at 3am, it\u2019s 30F outside, and the room has lost only 3F. In fact, the garage, with no heat of its own, is still 58F. This is an incredible difference, especially since heat rises.<\/p>\n<p>So on the first night, I\u2019m already pretty happy with this out of control project. This seems like a substantial energy improvement. Sure, it\u2019ll take a long time for this to pay for itself, but that wasn\u2019t my goal in the first place. I just wanted my wife to be able to control \u201cher\u201d door when she leaves for work...<\/p>",
            "date_published": "2021-03-13T13:24:37+00:00",
            "date_modified": "2021-03-13T13:24:34+00:00"
        },
        {
            "id": "eae20162-60c1-45a2-b618-20a3e52b1064",
            "url": "https:\/\/thezaz.com\/blog\/xojos_best_switch_control_just",
            "title": "Xojo's Best Switch Control Just Got Better",
            "content_html": "<p>I said I'd do it ages ago, and I finally have. ZirconSwitch revision 4 is now available as an open source control. You can find the project at <a href=\"https:\/\/github.com\/thommcgrath\/ZirconSwitch\">GitHub<\/a>, which has a zip archive for the full download in the releases section. The <a href=\"https:\/\/thezaz.com\/code\/zirconswitch\/\">product page<\/a> has been updated too.<\/p>\n<p>This new version is built using Xojo's API 2, so it requires Xojo 2019r2 or newer. The design has been updated to modern UI standards, so if you don't like the latest flat design trends, well then I'm sorry to disappoint. The control is backwards compatible with older versions of the control, though control sizing has been deprecated. That's not a bad thing. Rather than three control heights to choose from, it now renders the full height of the canvas so you can size it any way you wish.<\/p>\n<p>And being open source, it's free for everybody. Have at it.<\/p>",
            "date_published": "2021-01-06T18:52:21+00:00",
            "date_modified": "2021-01-06T18:52:17+00:00"
        },
        {
            "id": "d0b0829f-66d1-4d4d-a8d6-f05344d29287",
            "url": "https:\/\/thezaz.com\/blog\/xojo_cant_compare",
            "title": "Xojo Can't Compare",
            "content_html": "<p>I will never fault a developer for their bugs, because it's part of the job. We are imperfect humans trying to teach perfect computers how to do their jobs. But sometimes the bug fixing process goes wrong, and that's what this is all about.<\/p>\n<h3>The Bug<\/h3>\n<p>When a compiler has an arithmetic bug, it's embarrassing, but it happens. The bug gets fixed, and you move on with your life. When an arithmetic bug exists for 12 years without being fixed, that's disgraceful. When the developer categorically refuses to fix the bug, it's downright indefensible.<\/p>\n<p>Xojo has a problem comparing integers of differing types. This is because it tries to find a common type between the two types being compared, but there's no common type for many of the integer types.<\/p>\n<p>Here's an example of the problem:<\/p>\n<pre class=\"code\"><code class=\"language-xojo\"><span class=\"xojo_code_text\"><span class=\"xojo_code_keyword\">Var<\/span> FirstValue <span class=\"xojo_code_keyword\">As<\/span> <span class=\"xojo_code_keyword\">UInt32<\/span> = <span class=\"xojo_code_real\">4294967295<\/span>\n<span class=\"xojo_code_keyword\">Var<\/span> SecondValue <span class=\"xojo_code_keyword\">As<\/span> <span class=\"xojo_code_keyword\">Int32<\/span> = -<span class=\"xojo_code_real\">2147483648<\/span>\n<span class=\"xojo_code_keyword\">If<\/span> FirstValue &gt; SecondValue <span class=\"xojo_code_keyword\">Then<\/span>\n  <span class=\"xojo_code_comment\">\/\/ Won&apos;t Reach Here<\/span>\n<span class=\"xojo_code_keyword\">End<\/span> <span class=\"xojo_code_keyword\">If<\/span><\/span><\/code><\/pre>\n<p>The block will never be entered because FirstValue and SecondValue are considered equal. In an effort to compare the two, the compiler converts <code>FirstValue<\/code> into an Int32, which becomes the same value as <code>SecondValue<\/code>. While some developers will say the two types should not be compared, there's two issues I have with this logic.<\/p>\n<ol>\n<li>My first grader can figure out which is larger. So should the compiler.<\/li>\n<li>Xojo's target audience is people that don't understand the nuances of binary data.<\/li>\n<\/ol>\n<p>The bug becomes even more nasty though. Consider this code:<\/p>\n<pre class=\"code\"><code class=\"language-xojo\"><span class=\"xojo_code_text\"><span class=\"xojo_code_keyword\">Var<\/span> Value <span class=\"xojo_code_keyword\">As<\/span> <span class=\"xojo_code_keyword\">UInt32<\/span> = <span class=\"xojo_code_real\">4294967295<\/span>\n<span class=\"xojo_code_keyword\">If<\/span> Value &gt; <span class=\"xojo_code_integer\">100<\/span> <span class=\"xojo_code_keyword\">Then<\/span>\n  <span class=\"xojo_code_comment\">\/\/ Won&apos;t Reach Here<\/span>\n<span class=\"xojo_code_keyword\">End<\/span> <span class=\"xojo_code_keyword\">If<\/span><\/span><\/code><\/pre>\n<p>In a 32-bit application, this block will also never be entered for the same reason. <code>Value<\/code> gets converted to an Int32 to match the type of the literal 100.<\/p>\n<p>The workaround is to cast the literal into a UInt32:<\/p>\n<pre class=\"code\"><code class=\"language-xojo\"><span class=\"xojo_code_text\"><span class=\"xojo_code_keyword\">Var<\/span> Value <span class=\"xojo_code_keyword\">As<\/span> <span class=\"xojo_code_keyword\">UInt32<\/span> = <span class=\"xojo_code_real\">4294967295<\/span>\n<span class=\"xojo_code_keyword\">If<\/span> Value &gt; <span class=\"xojo_code_keyword\">CType<\/span>(<span class=\"xojo_code_integer\">100<\/span>, <span class=\"xojo_code_keyword\">UInt32<\/span>) <span class=\"xojo_code_keyword\">Then<\/span>\n  <span class=\"xojo_code_comment\">\/\/ You Will Reach Here<\/span>\n<span class=\"xojo_code_keyword\">End<\/span> <span class=\"xojo_code_keyword\">If<\/span><\/span><\/code><\/pre>\n<p>In a 64-bit application, comparing to 100 will work fine because <code>Value<\/code> will be converted to an Int64 which has no problem containing the value. However the problem still exists in 64-bit applications once larger values are reached:<\/p>\n<pre class=\"code\"><code class=\"language-xojo\"><span class=\"xojo_code_text\"><span class=\"xojo_code_keyword\">Var<\/span> Value <span class=\"xojo_code_keyword\">As<\/span> <span class=\"xojo_code_keyword\">UInt64<\/span> = <span class=\"xojo_code_real\">18446744073709551615<\/span>\n<span class=\"xojo_code_keyword\">If<\/span> Value &gt; <span class=\"xojo_code_integer\">100<\/span> <span class=\"xojo_code_keyword\">Then<\/span>\n  <span class=\"xojo_code_comment\">\/\/ Won&apos;t Reach Here<\/span>\n<span class=\"xojo_code_keyword\">End<\/span> <span class=\"xojo_code_keyword\">If<\/span><\/span><\/code><\/pre>\n<p>A 64-bit application really just means it'll be harder to <em>notice<\/em> the bug. It's still there.<\/p>\n<h3>The Reports<\/h3>\n<p>When I original ran into the bug, I found <a href=\"http:\/\/feedback.xojo.com\/case\/11935\">Case #11935<\/a> and added my sample project. It was opened and verified 10 years ago, while I was working for Xojo. That really bothered me that we let this was issue slip through the cracks. Turns out the original report is even older. <a href=\"feedback:\/\/showreport?report_id=2218\">Case #2218<\/a> is the 12 year old original, but closed as by design. Aaron Ballman makes the case that changing how the literal is interpreted will lead to subtle bugs, and he's absolutely right.<\/p>\n<p>The issue at hand is that only solves the problem when comparing against a literal. The issue is the comparison itself, not the literal. That's why Case #11935 is much more interesting, as Thomas Tempelmann proposes a solution. I'm not a compiler engineer, so I'm not sure how viable it is, but it's a potential solution.<\/p>\n<p>In an effort to get some attention in the issue, I made <a href=\"https:\/\/forum.xojo.com\/t\/something-funky-about-uint32-comparisons\/57447\">a forum thread<\/a>, and boy did it get attention. A few other solutions were proposed, such as using basic logic or doing the comparison with infinite precision integers. Just to reiterate, I'm not certain how viable each solution is, but there are potential solutions.<\/p>\n<h3>The Response<\/h3>\n<p>Xojo's response did not go as I expected. After 176 replies, they closed the forum post without any rules having been broken. Originally, their argument was that fixing the bug may break legacy code. It's a legit concern with any fix, but I can't think of any way that fixing a broken comparison would lead to broken code. <a href=\"https:\/\/forum.xojo.com\/t\/something-funky-about-uint32-comparisons\/57447\/89?u=thom_mcgrath\">I've asked Xojo for an example<\/a>, which they haven't provided. Nobody has been able to come up with an example of code that relies on comparisons being done incorrectly.<\/p>\n<p>If the bug were fixed, all of the above examples would begin to work, including the one with the explicit cast into UInt32. As much as I want this bug fixed, my intention is to prove Xojo <em>right<\/em>. I want to see code that would work worse with this fix in place than without the fix. So far I have been unable to do so.<\/p>\n<p>As that argument fell apart, Xojo's reasoning was shifted to a combination of \"it's not a bug\" and \"it's not worth fixing.\" Logically, it can't be both. It's either not a bug and therefore can't be fixed, or it's it is a bug but not worth fixing. And because of that, I have to believe that Xojo's excuse is just that: an excuse.<\/p>\n<p>On top of that, all the bugs reported on the issue have been closed. This prevents them from being ranked, and Xojo uses rank to evaluate their priorities. Part of their logic is since it's unranked, it doesn't affect a lot of people. But since it's closed, it can't be ranked. This equates to a \"stick your fingers in your ears and pretending it's not happening\" tactic.<\/p>\n<h3>The Conclusion<\/h3>\n<p>I believe the real reason they refuse to fix this bug is that they just <em>can't<\/em>. Xojo does not have a compiler engineer anymore. They don't have somebody on staff who is able to write the unit tests, evaluate the behavior, make the changes, and test the results. I know even if I were still with Xojo, I wouldn't be able to.<\/p>\n<p>This is an embarrassing bug and indefensible response. Please spread this. Put pressure on Xojo to fix the bug. Make noise. Based on the closing of the forum post, Xojo's goal is to ignore this until we forget about it. So my goal is to get this into the eyes of potential customers. What customer would want a tool that can't get its comparisons right?<\/p>",
            "date_published": "2020-10-02T16:08:32+00:00",
            "date_modified": "2020-10-02T16:08:24+00:00"
        },
        {
            "id": "6dae8c53-fccd-434d-a043-5a1068a5025d",
            "url": "https:\/\/thezaz.com\/blog\/yo_where_my_session_at",
            "title": "Yo where my session at?",
            "content_html": "<p>A <a href=\"https:\/\/forum.xojo.com\/t\/app-sessionatindex\/56911\/2\">thread on the Xojo Forum<\/a> finally made me realize one of the things I really dislike about Xojo's recent naming changes: never end a sentence with \"at.\" It's not technically an error, but it's less formal than I would expect for an API.<\/p>\n<p>We went from <code>SessionAtIndex(Index As Integer)<\/code> to just <code>SessionAt(Index As Integer)<\/code> and I can see what they were going for. But ending with \"At\" just rolls off the tongue like a brick rolls off a table. I think I would have preferred <code>Session(AtIndex As Integer)<\/code> but in that case the method name might not have been verbose <em>enough<\/em>. <code>GetSession(AtIndex As Integer)<\/code> wouldn't have been so bad and follows the VerbNoun pattern.<\/p>\n<p>What's done is done, but we're now forever stuck with <code>AddRowAt<\/code>, <code>RemoveRowAt<\/code>, <code>SessionAt<\/code>, and so on.<\/p>",
            "date_published": "2020-09-10T17:39:19+00:00",
            "date_modified": "2020-09-10T17:39:16+00:00"
        }
    ]
}