> ## Content Index
> Fetch the complete content index at: https://nolongerset.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Super-Safe Boolean Handling
- URL: https://nolongerset.com/super-safe-boolean-handling/
- Published: 2020-12-30T16:23:44.000Z
- Updated: 2026-05-08T13:07:08.000Z
- Description: If you want to be safe when working with Booleans, you need to ensure they're stored as 0 or -1. That's not as easy as you might think.
- Author: Mike Wolfe
- Tags: Advanced, Bug Alert, #Import 2026-05-20 02:59

I asked a question on Stack Overflow yesterday about some strange behavior I observed with the VBComponent.Saved property:

[VBComponent .Saved Boolean bug?Sub VBCompSavedBug() Dim VBComp As Object ’VBComponent With Application.VBE.ActiveVBProject Set VBComp = .VBComponents(1) End With Debug.Print TypeName(VBComp.Saved)![](https://cdn.sstatic.net/Sites/stackoverflow/Img/apple-touch-icon.png?v=c78bd457575a)Stack Overflowmwolfe02![](https://cdn.sstatic.net/Sites/stackoverflow/Img/apple-touch-icon@2.png?v=73d79a89bded)](https://stackoverflow.com/q/65501274/154439)

The problem, as I saw it, is that using the `CBool()` function alone is not enough to guarantee that a value will be coerced into a safe and reliable Boolean. What do I mean by a "safe and reliable Boolean"? I mean one that is stored as either a 0 or -1\. 

If the boolean value is not stored as a 0 or -1, then it's prone to [causing subtle bugs](https://nolongerset.com/deceptively-complex-booleans/). I'm talking about bugs like this where applying **Not** to a True value results in...a True value:

```vba
x = 1
?CBool(x)
True
?CBool(Not x)
True
```

This occurs because Not is a bitwise operator and any number that is not zero is considered True.

### CBool() to the rescue?

The problem in the example above is that we applied the Not operator directly to the integer value 1\. This converted the value of 1 to -2 instead of 0\. When we converted -2 to Boolean, it then returned True:

```vba
x = 1
?Not x
-2
?CBool(-2)
True
```

But, what if we converted 1 to Boolean *before* we applied the Not operator? This will work because CBool(1) will force the value to be stored as -1:

```vba
x = 1
?CBool(x)
True
?Not CBool(x)
False
?CInt(CBool(x))
-1
```

### CBool() works...unless it doesn't

This brings me back to the question I posted to Stack Overflow. I was working with the VBComponent.Saved property. The .Saved property is a Boolean. But--and this is a big "but"--the True value of the .Saved property is a 1:

```vba
Set VBComp = Application.VBE.ActiveVBProject.VBComponents(1)
?VBComp.Saved
True
?TypeName(VBComp.Saved)
Boolean
?CInt(VBComp.Saved)
 1 
```

What's the big deal? Only this:

```vba
Set VBComp = Application.VBE.ActiveVBProject.VBComponents(1)
?VBComp.Saved
True
?Not VBComp.Saved
True
```

OK, that's not ideal. It can lead to all sorts of hard-to-find bugs. But we know how to fix this, right? We'll just coerce it to Boolean before applying the Not operator. Just like we did earlier. Here we go:

```vba
Set VBComp = Application.VBE.ActiveVBProject.VBComponents(1)
?CBool(VBComp.Saved)
True
?Not CBool(VBComp.Saved)
True
```

Oh no! CBool() works until it doesn't! What the heck is going on here? Let's go check the VBA spec for some sort of explanation.

### Let-coercion to and from Boolean

This is the fancy name for what's actually going on here. When we convert between types in VBA--either explicitly via CBool() or implicitly via context--the VBA language specification provides rules that govern the operation. Here are the rules when [coercing to and from Boolean types](https://docs.microsoft.com/en-us/openspecs/microsoft%5Fgeneral%5Fpurpose%5Fprogramming%5Flanguages/ms-vbal/3a9f5227-5fd5-4240-949a-51ffc32e71a9):

![](https://storage.ghost.io/c/eb/d7/ebd732c1-5f03-4f07-b386-5d08557e15c9/content/images/2020/12/image-27.png)

When we are converting from a Boolean to a Boolean, the language merely copies the source value. That is, **applying CBool() to a Boolean has no effect.**

And that has real consequences when we're dealing with a Boolean data type that is stored as something other than 0 or -1.

### A reliable approach

So, given what we know, how can we coerce any value to a Boolean and ensure that it is only represented by a 0 or -1? For any types but Booleans, we just need to coerce it to boolean using the CBool() function. But we've already established that won't work for Booleans.

Here's my proposed three-step process:

1. Explicitly coerce the value to Boolean (in case it's not already)
2. Explicitly coerce the value to Integer (in case the original value was a boolean)
3. Explicitly coerce the value to Boolean

Here's the very ugly code that makes this happen: `CBool(CInt(CBool(x)))`

Let's test this approach on a few values:

```vba
x = 111222333
?CBool(CInt(CBool(x)))
True
?Not CBool(CInt(CBool(x)))
False
```

Note that without the inner CBool() the above code would have resulted in an overflow when we coerced `x` to an integer.

Now, let's revisit the original problem, VBComp.Saved:

```vba
Set VBComp = Application.VBE.ActiveVBProject.VBComponents(1)
?CBool(CInt(CBool(VBComp.Saved)))
True
?Not CBool(CInt(CBool(VBComp.Saved)))
False
```

Hey, look! It works now!

### Recap

Booleans in VBA are fraught with hidden risk. The seemingly obvious approach of forcing values to boolean using the **CBool()** function is not enough to avoid all those risks. The only reliable way I know of is to make it a three-part conversion:

```vba
CBool(CInt(CBool(x)))
```

---

***UPDATE:*** No sooner did I publish this article than Wayne Phillips pointed out a simpler (and almost certainly more performant) approach to achieve the same objective:

> \>> CBool(CInt(CBool(x)))  
>  
> What about this instead....  
> x <> False
> 
> — EverythingAccess.com (@WaynePhillipsEA) [December 30, 2020](https://twitter.com/WaynePhillipsEA/status/1344338916577521667?ref%5Fsrc=twsrc%5Etfw)

Sure enough, Wayne's approach is spot on:

```vba
Set VBComp = Application.VBE.ActiveVBProject.VBComponents(1)
?VBComp.Saved <> False
True
?Not (VBComp.Saved <> False)
False
```

Thanks, [Wayne](https://twitter.com/WaynePhillipsEA)!

*Image by [Yerson Retamal](https://pixabay.com/users/voltamax-60363/?utm%5Fsource=link-attribution&utm%5Fmedium=referral&utm%5Fcampaign=image&utm%5Fcontent=1636390) from [Pixabay](https://pixabay.com/?utm%5Fsource=link-attribution&utm%5Fmedium=referral&utm%5Fcampaign=image&utm%5Fcontent=1636390)*