UtterAccess.com
X   Site Message
(Message will auto close in 2 seconds)

Welcome Guest ( Log In | Register )

 
Reply to this topicStart new topic
> If Not True Then...    
 
   
jleach
post Jul 10 2010, 08:20 PM
Post #1

UtterAccess Editor
Posts: 6,717
From: Capital District, NY, USA



Hi all,

Often when coding, I'll use a line such as the following for comparison of a boolean or numeric value:

CODE
If [Value] Then
  'this value is true (or at least not 0)
End If


so this evening I was working on some code, and put the following:

CODE
Dim Ret As Boolean
Ret = SomeFunctionReturningBoolean()
If Not Ret Then
  'ret should = false...
Else
  'ret should = true...
End If


however, the above "If Not Ret Then" doesn't seem to work correctly (or, I don't have the understanding of why this is not working like I would expect).

The 'ret should = false part of the condition is running when Ret = True. The condition Not True is returning True.

?Not True
False

I event used parentheses...

?(Not True)
False

So the expression "Not True" returns False, yet
the conditional expression "Not True" returns true...

Thoughts? (IMG:style_emoticons/default/iconfused.gif) I will rearrange my code to exclude the Not keyword in the expression (I'll never trust Not True again...this is what I get for not using "If Ret = False"). At this point I'm just extremely curious how the conditional expression is returning what seems to be an erroneous value.

Thanks,
Go to the top of the page
 
+
Steve Schapel
post Jul 10 2010, 08:54 PM
Post #2

UtterAccess VIP
Posts: 3,881
From: New Zealand



Jack,

I have been unable to replicate the behaviour you described. (IMG:style_emoticons/default/iconfused.gif)
Go to the top of the page
 
+
Steve Schapel
post Jul 10 2010, 08:58 PM
Post #3

UtterAccess VIP
Posts: 3,881
From: New Zealand



Jack,

Just to expand upon my earlier reply, I run this:

CODE
   Dim Ret As Boolean
   Ret = True
   If Not Ret Then
      MsgBox "F"
   Else
      MsgBox "T"
   End If

... I get a message box with "T"

I run this:

CODE
   Dim Ret As Boolean
   Ret = False
   If Not Ret Then
      MsgBox "F"
   Else
      MsgBox "T"
   End If

... I get a message box with "F"

Is that what you would expect?
Go to the top of the page
 
+
jleach
post Jul 10 2010, 09:10 PM
Post #4

UtterAccess Editor
Posts: 6,717
From: Capital District, NY, USA



QUOTE
CODE
Dim Ret As Boolean
Ret = True
If Not Ret Then
   MsgBox "F"
Else
   MsgBox "T"
End If


... I get a message box with "T"


The above is what I would expect... I'm a losing my mind, or...

the attached image clearly shows that ret = true, but Not ret is calculating as true?
Attached File  New_Bitmap_Image.bmp ( 102.43K ) Number of downloads: 17


edit: not sure how to get the thumbnail, sorry...
Go to the top of the page
 
+
jleach
post Jul 10 2010, 10:30 PM
Post #5

UtterAccess Editor
Posts: 6,717
From: Capital District, NY, USA



If anyone wants to take a look and see if they're getting the same behavior, attached is a copy of the class I'm trying to put together where this is happening.

There's two modules, Module1 and clsGetOpenFile.

The function GetFile of clsGetOpenFile is where I'm seeing the behavior. The code below is the conditional that it's happening on.

CODE
  'make the call and handle the return
  ret = apiGetOpenFileName(OFN)
  If Not ret Then
    GetFile = Null  '<--- this line is running when ret = True
  Else
    If Not MultiSelect Then
    '....



Run the function testit() with a breakpoint on clsGetOpenFile.GetFile() If Not ret Then


MS Access 2003 (11.8166.8221) SP3
Vista Home Premium 6.0.6002
Attached File(s)
Attached File  clsGetOpenFile.zip ( 34.99K ) Number of downloads: 4
 
Go to the top of the page
 
+
WaynePhillips
post Jul 11 2010, 01:09 AM
Post #6

UtterAccess Addict
Posts: 156
From: Cheshire, England



Hi Jack,

If we look at the official Windows documentation for the API function GetOpenFileName, then you will see that the return value is declared as BOOL. In C, a 'BOOL' resolves to an 'int', which is a 32-bit value. Conceptually, for BOOL, a zero is considered False and all non-zero values in the 32bit space are considered True.

In VBA, the Boolean data type is actually only a 16-bit number. So first off, the API declaration is wrong - you should really declare it with a Long return type like this:

CODE
Private Declare Function apiGetOpenFileName _
  Lib "comdlg32.dll" _
  Alias "GetOpenFileNameA" _
  ( _
    OFN As OPENFILENAME _
  ) As Long


A VBA Long is the closest equivalent to a BOOL in C. Now if you look at the documentation again, you'll see "If the user specifies a file name and clicks the OK button, the return value is nonzero", which is what we expect, so now change the call to the API function to:

CODE
ret = apiGetOpenFileName(OFN) <> 0


And that will sort this problem out for you.

In reality though, GetOpenFileName tends to return a zero on failure, and a 1 on success. That 1 value, when treated as a VBA Boolean datatype, is considered as "True" by VBA during normal evaluation (as all-non-zero values are), but VBA expects the value to actually be -1 (&HFFFF, all bits sets). The Not operator is actually doing a bitwise operation on the value, and therefore wheras normally the -1 becomes 0, your 1 actually becomes -2:

CODE
?Not -1
0
?Not 1
-2


So now VBA is reading -2 as a Boolean type, and it is therefore being considered as True, when you expected False.

In my view, it's a bug in VBA since it really should be doing a logical-Not for Booleans, not a bitwise-Not.

This post has been edited by WaynePhillips: Jul 11 2010, 01:10 AM
Go to the top of the page
 
+
jleach
post Jul 11 2010, 07:07 AM
Post #7

UtterAccess Editor
Posts: 6,717
From: Capital District, NY, USA



Now that's interesting. Thanks for taking the time to look at it... had me stumped for sure.

It struck me a little odd that the API was declared as Boolean, I don't think I've ever seen that before (they're just about always Long, I think). But I didn't give it any further thought, and certainly never guessed that this would be a result of it.

Cheers,
Go to the top of the page
 
+
jleach
post Jul 12 2010, 08:38 AM
Post #8

UtterAccess Editor
Posts: 6,717
From: Capital District, NY, USA



For any interested, I made an attempt to recreate this behavior within VBA (not external calls), and was not able to get the boolean variable bits set so that the result was recreated. E.g. - within VBA, this "bug" does not seem to be possible, as no matter what numeric value aside from 0 you set the boolean to, apparently VBA will set all the bits to 1 (resulting in a numeric value of -1 for the boolean).

CODE
Public Function TestIt()

  Dim b As Boolean
  b = 1
  Debug.Print "CInt(b) = " & CInt(b)
  Debug.Print "b = " & b
  Debug.Print "Not b = " & Not b

End Function


CODE
testit
CInt(b) = -1
b = True
Not b = False


That's a little more settling.

Go to the top of the page
 
+
datAdrenaline
post Aug 9 2010, 12:46 AM
Post #9

UtterAccess Editor
Posts: 15,974
From: Northern Virginia, USA



I know this is an older thread, but I had to join in the fun ... (IMG:style_emoticons/default/smile.gif) ...

Also, as a point of note, by convention, many databases and programming languages define False as 0, and True as not equal to 0. Assigning a constant of -1 to True in VBA, is (IMO) a really cool conveinience, but there are tricky things to know ...

CODE
If 32000 Then
    Debug.Print "This branch will be taken"
End If


But we all know that 32000 does not equal True ... however ... 32000 is definately not False, or rather not equal to 0, thus the branch is taken.

----

? 32000 = True
False

? 32000 <> False {Shows that comparison to <> False is different than comparing to True!}
True

? True = CByte(255)
True {Tricky eh? ... I thought the Byte datatype was from 0 to 255, and True was -1? (IMG:style_emoticons/default/smirk.gif) }

? -1 = CByte(255)
False {Even trickier!}

? CInt(True)
-1

? CByte(True)
255

? CByte(-1)
--> Overflow error ... {I thought true was -1 ?? (IMG:style_emoticons/default/evilgrin.gif) }

... I love boolean (not the data type) math ... Cool eh?


As a side note, the value being stored in "b" of your code was NEVER 1 ... since you declared the Type as Boolean, VBA coerces any number assigned to a boolean variable as 0 or -1. Do note that you can change your code up a bit (declare b as an Integer) ... and you will see what Wayne was speaking about regarding logical Not and bitwise Not.
Go to the top of the page
 
+
BananaRepublic
post Aug 9 2010, 12:57 AM
Post #10

Rent-an-Admin
Posts: 8,768
From: Banana Republic



Brent -

I know we had a recent-ish thread where we touched on that subject and that was actually the same thread I was thinking about when we talked about how one should be careful to not assume the converse will succeed.

From this:

CODE
If a Then


We should not assume the converse would be:

CODE
If Not a Then


which will produce unexpected results (albeit only if the variable a is not a boolean datatype; but too many times we make implicit conversion from non-boolean data types to a boolean data types using bitwise NOT operator and that will blow up). A proper converse of the "If a Then" ought to be:

CODE
If a = 0 Then


or similar derivatives. It does seem odd but it is in fact consistent with general definitions in many programming languages where false = 0 and true = NOT false (but how the true may be interpreted can depend on which programming language we may be using - in VBA it happens to be -1, but in other languages, it happens to be 1 even though the logical test only checks whether the value is zero or nonzero and thus doesn't care what actual number we are using).

So yeah, that's the thread I was thinking in the other thread. Only thing, though, I can't remember where that other thread we had that discussion is.... (IMG:style_emoticons/default/smirk.gif)
Go to the top of the page
 
+
jleach
post Aug 9 2010, 05:10 AM
Post #11

UtterAccess Editor
Posts: 6,717
From: Capital District, NY, USA



Since the incident that caused this thread to be, I've taken a lot more wary approach to some coding methods that I used to use. For whatever reason, it seems easier (or maybe more elegant) to use "If Not Value Then" rather than "If Value = False Then".

But I've come to realize how tricky this can be. I've also tended to stray away from booleans on the whole and use integers instead (I've been doing this in table structures for quite some time, more recently in VBA as well).

If 1234 <> 0
If 1234 = 0

Not much trickery in that...


Cheers!
Go to the top of the page
 
+
datAdrenaline
post Aug 9 2010, 09:37 AM
Post #12

UtterAccess Editor
Posts: 15,974
From: Northern Virginia, USA



QUOTE (BananaRepublic @ Aug 9 2010, 01:57 AM) *
Brent -

I know we had a recent-ish thread where we touched on that subject and that was actually the same thread I was thinking about when we talked about how one should be careful to not assume the converse will succeed.


- probably this one (IMG:style_emoticons/default/smile.gif)

In there you mentioned that if you wish to use the numerics, its safest to do something like this:

If CBool(X) Then ...
If Not CBool(X) Then ...

{Where X is a varible of a numeric type}

----

But ... one thing to realize, if we care to delve deep into the subject, is that the conditional --- way down at the machine code level --- is implicitely compared to 0 ... so when we write:

If 32000 Then ...

When it breaks down to machine code, it would look something like:

If 32000 <> 0 Then ...

EVEN if we explicitly compare to a value or boolean ... the expression will be implicitely compared to 0, so ...

If 1 > 0 Then ...

Will eventually become something that can be represented like this ...

If (1 > 0) <> 0 Then ...

That concept of ALWAYS evaluating the conditional with an implicit comparison to 0 to determine vericity of the condition is, IIRC, a program language/compiler "definition" of sorts. I expand on that in this post/topic discussion.

{remember, my scope is at the machine level ... the itermediate language may still look different than my claims --- Wayne can shed some like on that (IMG:style_emoticons/default/smile.gif) }
Go to the top of the page
 
+
BananaRepublic
post Aug 9 2010, 09:38 AM
Post #13

Rent-an-Admin
Posts: 8,768
From: Banana Republic



QUOTE (jleach @ Aug 9 2010, 05:10 AM) *
Since the incident that caused this thread to be, I've taken a lot more wary approach to some coding methods that I used to use. For whatever reason, it seems easier (or maybe more elegant) to use "If Not Value Then" rather than "If Value = False Then".


I understand, but I would point out that if the value is a boolean data type, then it'll work just as expected. If we have a variable named "a" of boolean data type and it is set to True (aka -1), "If Not a Then" will succeed just fine. It's when we use integers things get interesting. If an integer "a" is given a value of 1, doing "If Not a" will evaluate the "Not a" to -2, which is technically still True but maybe we had intended that "this branch ought to be taken if the value of a is not false .... e.g. nonzero." and that would backfire on us.

But I've come to realize how tricky this can be.

QUOTE
I've also tended to stray away from booleans on the whole and use integers instead (I've been doing this in table structures for quite some time, more recently in VBA as well).


I have to wonder why you decided to avoid booleans? There is nothing wrong with booleans and as I pointed out, one is more likely to run into troubles with integers because the evaluation is inherently boolean. Now,

QUOTE
If 1234 <> 0


Just as a matter of interest, I read in an Access book that it's slightly faster to do this:
CODE
If Not (1234 = 0)


But the difference is likely miniscule that it may not be worth justifying typing the extra characters. That said, I tend to do something similar in SQL where I imagine there is more benefit since it's bulk processing.

QUOTE
Not much trickery in that...


I certainly can agree that doing this way is more readily apparent than doing "If a Then" then "If a=0 Then" which will indeed appear odd to the future developers.
Go to the top of the page
 
+
BananaRepublic
post Aug 9 2010, 09:45 AM
Post #14

Rent-an-Admin
Posts: 8,768
From: Banana Republic



QUOTE (datAdrenaline @ Aug 9 2010, 09:37 AM) *


Yes, that's the one. Thanks.

QUOTE
In there you mentioned that if you wish to use the numerics, its safest to do something like this:

If CBool(X) Then ...
If Not CBool(X) Then ...

{Where X is a varible of a numeric type}


As mentioned here, we also can do the same thing with:

If X Then
If X = 0 Then

which I'd suspect is so ever slightly faster since there's no need for conversions or operations prior to evaluating - we get to evaluation directly. The only trouble, though is that it's not immediately readable to the other coders whereas the variant using CBool() is certainly more readable.


Tangent: I just remembered that long ago, I downloaded a code sample from a place and saw that the developer had interesting take. Instead of futzing with the "not" part, he did this:
CODE
If X Then
Else
   ...
End If


The branch for True part was empty so if the result was True, nothing was done. If it was not True, then Else branch is taken and something extra happens. I have yet to see that convention again somewhere else. That is also arguably more "readable" than "If X = 0", for sure. Whether it's as fast, I'm not as sure; maybe not due to extra instruction needed to jump to the Else branch?

QUOTE
That concept of ALWAYS evaluating the conditional with an implicit comparison to 0 to determine vericity of the condition is, IIRC, a program language/compiler "definition" of sorts. I expand on that in this post/topic discussion.

{remember, my scope is at the machine level ... the itermediate language may still look different than my claims --- Wayne can shed some like on that (IMG:style_emoticons/default/smile.gif) }


100% agreed on that most (if not all) programming languages always start with False = 0 and work from there. (IMG:style_emoticons/default/smile.gif)
Go to the top of the page
 
+
jleach
post Aug 9 2010, 10:31 AM
Post #15

UtterAccess Editor
Posts: 6,717
From: Capital District, NY, USA



QUOTE
I understand, but I would point out that if the value is a boolean data type, then it'll work just as expected.


Most of the time, yes... but not always. My original post was based on this sole principle (which I wasn't aware of at the time). If everything you are doing is within VBA, then, yes, I supsect that statement is entirely true. But when we branch out from there, we can run into issues.

In my original code that this thread was based on, I have an API call declared with a (VBA) Boolean return, after which a conditional check of Is Not <API> Then... which was failing because the Not operator was (is) performing a bitwise comparison on the boolean value returned by the API.

Understood that, in normal cases, the VBA Boolean will work with the Not operator as expected, but as I came to realize, this is not the case across the board when the ends of the board are dipping into things that are not VBA. Call this bad programming practice on my part - e.g. - not declaring the proper return type for the API, but at the end of the day, one would expect a VBA boolean to operate as a boolean (proper return using the Not operator). One would think that a Boolean variable in VBA would either be True, or False... not a combination of bits that can be misread in a conditional in the rare case that an unwary developer (or even a wary developer without the proper knowledge) may run into trouble with.

My first decisions to start avoiding the use of yes/no fields in table structures came from Allen Browne:

http://allenbrowne.com/NoYesNo.html

... and in the years following, I've found both the yes/no and the boolean (not exactly the same, right? further conversation??) to be, more of less, a confusing mess when one tries to figure out the nitty gritty of them. Personally, I don't like anything I don't/can't understand.

I understand that a Boolean variable is a set of bits that are set to either 0's or 1's, respectively False or True. I understand that an API call can coerce the bits of this value to something that we don't expect or often consider in vba programming, and I further understand that using a bitwise Not operator against this "mixed-bit" value can return something that will not be the same as the logical Not operator performed on a Boolean variable.

To me, Not False = True; Not True = False, and, IMVHO, that is all we should need to know about a boolean variable.

So, am I right to assume that boolean variables are tricky things with a pretty face and ugly insides that lurk in the shadows waiting to screw our day up? Probably not. Probably if I were more concise about how I code (If (Ret <> 0) = False Then rather than If Not Ret), it wouldn't be an issue.

Probably the deeper problem for me is the use of the Not operator, expecting a Logical not while it is instead performing a bitwise Not.

For a boolean, I never really understood why they are what they are. What's wrong with using a single bit to store the value of the boolean? 0 or 1, right? The only answer that we ever want or expect when consulting a boolean variable is a straightforward Yes or No; True of False; 0 or 1... not some mixed up mess of bits that a bitwise Not (and how about And or Or?) miscalculates (or at least gives us an answer that we wouldn't expect).

I suppose this probably has something to do with the CPU processing - processors aren't set up to handle a single bit comparison on an application level, right? To efficiently use a CPU, it reads in a certain number of bits at a time, and hence why we have what is supposed to be a simple yes/no being instead a list of bits with these vulnerabilities. Anyway, this stuff is all way beyond me.

All In-My-Very-Humble-Opinion of course, but when I say "Is 1234 equal to 0?" I completely understand the answer that my code will give me.

This is why I've come to dislike the use of booleans.

What a mess!


Cheers,
Go to the top of the page
 
+
BananaRepublic
post Aug 9 2010, 11:18 AM
Post #16

Rent-an-Admin
Posts: 8,768
From: Banana Republic



QUOTE (jleach @ Aug 9 2010, 10:31 AM) *
Most of the time, yes... but not always. My original post was based on this sole principle (which I wasn't aware of at the time). If everything you are doing is within VBA, then, yes, I supsect that statement is entirely true. But when we branch out from there, we can run into issues.

In my original code that this thread was based on, I have an API call declared with a (VBA) Boolean return, after which a conditional check of Is Not <API> Then... which was failing because the Not operator was (is) performing a bitwise comparison on the boolean value returned by the API.


Ah, I thought I had read it that we were using integers as a return type initially. Even so, it goes back to the original point: If we do an implicit conversion of integers to boolean, we may get unexpected results.

In some ways I find it unfortunate that VBA (and VB as well) engage in some trickery when processing API calls. You may recall me linking to a light article discussing how strings are handled between the worlds which requires careful examination and correctly declaring ByVal/ByRef among other things. Now, I can't say I've studied closely the VBA's handling of numeric and boolean results from outside the world, I'd imagine that because C has no boolean data type, it's going to be a integer data type. I'm not sure if C++ natively defines a boolean data type but even if it did, it's probably "just another way to represent a byte" in very much like fashion as a char could be read as a number even if that is not the intended representation of the data.

QUOTE
Understood that, in normal cases, the VBA Boolean will work with the Not operator as expected, but as I came to realize, this is not the case across the board when the ends of the board are dipping into things that are not VBA. Call this bad programming practice on my part - e.g. - not declaring the proper return type for the API, but at the end of the day, one would expect a VBA boolean to operate as a boolean (proper return using the Not operator). One would think that a Boolean variable in VBA would either be True, or False... not a combination of bits that can be misread in a conditional in the rare case that an unwary developer (or even a wary developer without the proper knowledge) may run into trouble with.


Right, but we don't have to go outside VBA to see this effect. We can see the same thing inside VBA when we do any implicit conversions from numeric to booleans. I'd say that implicit conversions has done more harm to any developers than anything else and I'd love to see this in next version of VBA:

CODE
Option Do_Not_Do_That_Voodoo_Implicit_Conversion


Actually, this already exists in VB.NET as "Option Strict" (but I like my variant better. (IMG:style_emoticons/default/smirk.gif) ). But the fundamental point here is that because to computer, everything is either 0s or 1s, it's all relative to what we say what this collection of 0s and 1s ought to represent, and being human we are, we're very consistent... except when we aren't. (IMG:style_emoticons/default/wink.gif) Hence, we get 1 as a True value in some programming languages while it's -1 in VBA.

QUOTE
My first decisions to start avoiding the use of yes/no fields in table structures came from Allen Browne:

<link>

... and in the years following, I've found both the yes/no and the boolean (not exactly the same, right? further conversation??) to be, more of less, a confusing mess when one tries to figure out the nitty gritty of them. Personally, I don't like anything I don't/can't understand.


I certainly emphasize with Yes/No fields which I've likewise found problematic. You are correct they're not exactly same thing since Yes/No is a Jet data type and Boolean is a VBA data type. Long ago, Brent and I talked about the size of this and concluded that VBA Boolean data types were actually 2 bytes, or equivalent to an Integer data type. I *think* Jet's Yes/No is actually one byte, though the Access documentation will say it's 1 bit, but we've not found this to be the case.

QUOTE
I understand that a Boolean variable is a set of bits that are set to either 0's or 1's, respectively False or True. I understand that an API call can coerce the bits of this value to something that we don't expect or often consider in vba programming, and I further understand that using a bitwise Not operator against this "mixed-bit" value can return something that will not be the same as the logical Not operator performed on a Boolean variable.

To me, Not False = True; Not True = False, and, IMVHO, that is all we should need to know about a boolean variable.


But you're not asking what is exactly False and what is exactly a True? Such concept is utterly meaningless to a mindless computer that's nothing but a big fancy calculator with piles of gates. Everything has to be represented in 0s and 1s and we found it convenient to say False = 0 and True = Not False. As Brent said, people get tripped up when they try to compare things to the True value which cannot be same thing as "(logical) Not False" because all the computer can see is 0s and 1s and tries to evaluate the thing as "a = -1" which isn't what we asked.

QUOTE
So, am I right to assume that boolean variables are tricky things with a pretty face and ugly insides that lurk in the shadows waiting to screw our day up? Probably not. Probably if I were more concise about how I code (If (Ret <> 0) = False Then rather than If Not Ret), it wouldn't be an issue.


Understandable, but I would also point out that boolean doesn't have the monopoly on the ugly insides. We run into the same problems with how we ought to represent a string and objects which are actually pointers behind the curtains. I would recommend reading Joel Spolsky's Law of Leaky Abstractions. It's quite entertaining and provocative article.

QUOTE
Probably the deeper problem for me is the use of the Not operator, expecting a Logical not while it is instead performing a bitwise Not.

For a boolean, I never really understood why they are what they are. What's wrong with using a single bit to store the value of the boolean? 0 or 1, right? The only answer that we ever want or expect when consulting a boolean variable is a straightforward Yes or No; True of False; 0 or 1... not some mixed up mess of bits that a bitwise Not (and how about And or Or?) miscalculates (or at least gives us an answer that we wouldn't expect).

I suppose this probably has something to do with the CPU processing - processors aren't set up to handle a single bit comparison on an application level, right? To efficiently use a CPU, it reads in a certain number of bits at a time, and hence why we have what is supposed to be a simple yes/no being instead a list of bits with these vulnerabilities. Anyway, this stuff is all way beyond me.


Yes, generally speaking, everything is processed as bytes, not as bit though it is technically possible to use bits. However, to do bitwise operations would be comparatively more costly than processing a byte. Brent and I both talked about the suspicion that VBA Boolean was 2 byte because it was more efficient to process it as such than any smaller units. I'm not sure if that is satisfactory explanation but well, you go.

QUOTE
All In-My-Very-Humble-Opinion of course, but when I say "Is 1234 equal to 0?" I completely understand the answer that my code will give me.

This is why I've come to dislike the use of booleans.


Yes, there is something to be said for being explicit.

QUOTE
What a mess!


I think you mean "What a leak!" (IMG:style_emoticons/default/ohyeah.gif)
Go to the top of the page
 
+
datAdrenaline
post Aug 9 2010, 12:03 PM
Post #17

UtterAccess Editor
Posts: 15,974
From: Northern Virginia, USA



Hello Jack,

I was thinking of a lot to say when reading your, but I am running short on time ... so I will just hilite these few things:

>> In my original code that this thread was based on, I have an API call declared with a (VBA) Boolean return, after which a conditional check of Is Not <API> Then... which was failing because the Not operator was (is) performing a bitwise comparison on the boolean value returned by the API. <<

API's indeed modify memory space as you noted, and with your declaration as a Boolean as apposed to Long problems will arise. The whole issue, to me, is not with the Boolean datatype or the Not operator they are doing exactly as they are decribed to do. In fact, your code would have worked just fine if the API call was declared as a Long. Let me explain: With the declaration of the api being Boolean and with the code line of:

Ret = apiGetOpenFileName(OFN)

The VBA compiler saw no need to coerce the supposed "boolean" bits set by apiGetOpenFileName(OFN) to a set of boolean bits expected by Ret, this is what enabled Ret to get a bit pattern equivalent to the value of 1. However, if apiGetOpenFileName(OFN) was properly declared as a Long, the VBA compiler would recognize the datatype discrepancy and implicitly coerce the value of the Long result supplied by apiGetOpenFileName(OFN) into the boolean datatype expected by Ret, which would yeild a bit pattern stored in Ret that would be equivalent to -1.

By the way, please do not think I am trying to indicate that this is/was a simple thing to debug --- quite the opposite really, and a big (IMG:style_emoticons/default/thumbup.gif) to Wayne for recognizing the incorrect declaration!

>> Not operator, expecting a Logical not while it is instead performing a bitwise Not. <<

The NOT operator is a dual purpose operator (logical negation AND bit inversion), VBA determines how to use it by its context.

Ok Ok ... It's likely always doing the bitwise thing, since inverting False (0) results in True (-1) and inverting True (-1) results in False (0) --- so the "Logical inversion" is simply a result of inverting a Boolean datatype ... b u t ... I just thought I would point out that VBA help does indeed discuss that fact that bitwise inversion is what Not does. To quote:
"In addition, the Not operator inverts the bit values of any variable .."


>> If (Ret <> 0) = False Then rather than If Not Ret <<

If Ret <> 0 Then ...

Or ..

If Ret = 0 Then ...

Is really all you need to be clear and consistent (IMG:style_emoticons/default/smirk.gif)
Go to the top of the page
 
+
WaynePhillips
post Aug 9 2010, 12:37 PM
Post #18

UtterAccess Addict
Posts: 156
From: Cheshire, England



Sorry guys, I completely forgot about this thread - didn't realise the discussion had moved on a bit (IMG:style_emoticons/default/smile.gif)

QUOTE
However, if apiGetOpenFileName(OFN) was properly declared as a Long, the VBA compiler would recognize the datatype discrepancy and implicitly coerce the value of the Long result supplied by apiGetOpenFileName(OFN) into the boolean datatype expected by Ret, which would yeild a bit pattern stored in Ret that would be equivalent to -1.


Absolutely correct. The <>0 is certainly optional here and it is of course personal preference as to whether you use it in this case. Personally I would as it then explicitly matches the API documentation.

Some good discussion going on here. It's also handy to remember that a VBA Boolean datatype maps directly to a VARIANT_BOOL data type in C (defined in one of the OLE header files). So, only when the C definition of an API specifies VARIANT_BOOL should you ever define your VBA API Declares with Boolean data types.
Go to the top of the page
 
+
BananaRepublic
post Aug 9 2010, 12:47 PM
Post #19

Rent-an-Admin
Posts: 8,768
From: Banana Republic



QUOTE (WaynePhillips @ Aug 9 2010, 12:37 PM) *
Personally I would as it then explicitly matches the API documentation.


I agree as well. However, I think it's fair that this can be quite an undertaking. I'd wager that if given the choice, VBA developers would sooner go to mentalis.org and grab a VB-compatible API declaration than going to MSDN and deciphering comparatively byzantine C data types. I also believe that over the time, this will become more and more necessary since there's no longer active VB development (on which we rode the coattails), and as we need to adapt to newer API that are compatible on Vista or newer OS as well 64-bit compatible declarations.

It's easy enough to say, map a VBA String data type to OLE's BSTR, but when we're dealing with one of many different string data types, it's hard to be certain that the mapping is what we expected.
Go to the top of the page
 
+
WaynePhillips
post Aug 9 2010, 01:07 PM
Post #20

UtterAccess Addict
Posts: 156
From: Cheshire, England



Very true, Banana.

And then you've also got other issues to contend with such as the automatic BSTR-to-Ansi conversions that occur behind the scenes for String declares made in the VBE (but not for declares that are made in a type-library). It's a mine-field if you don't know what you're doing, and I can certainly understand why most developers just get the declerations from the net without checking them (or without knowing how to check them).

<rant on>Another one that happens all too often: using "Integer" wrongly as a datatype in declares. You very rarely see a C API decleration using a "short int" which is what a VB Integer actually maps to. Using Integer truncates the high-16 bits of the value, so it's important to get it right (as a Long).<rant off>

This post has been edited by WaynePhillips: Aug 9 2010, 01:21 PM
Go to the top of the page
 
+

Thank you for your support! Reply to this topicStart new topic

Jump To Forum:
 



RSS Go to Top  ·  Lo-Fi Version Time is now: 22nd May 2013 - 05:53 AM