|
-
Nov 18th, 2018, 05:58 PM
#1
Thread Starter
Frenzied Member
Interesting Find - ByRef Mismatch - Integer vs Byte
Just found an interesting situation here.....
Assuming we have this simple Sub:
Code:
Private Sub simpleTest(index As Integer)
MsgBox index, vbOKOnly
End Sub
Private Sub Form_Load()
Dim mBox As Byte
simpleTest mBox '//This gives a byRef error as the mBox variable is a Byte and expecting an Integer.
simpleTest (mBox) '//This in brackets however, seems ok
End Sub
I'm assuming that the brackets is changing the variable type to a varient ?
_____________________________________________________________________
----If this post has helped you. Please take time to Rate it.
----If you've solved your problem, then please mark it as RESOLVED from Thread Tools.

-
Nov 18th, 2018, 06:06 PM
#2
Re: Interesting Find - ByRef Mismatch - Integer vs Byte
I believe the gratuitous use of parentheses tells the compiler: "Evaluate this expression then coerce and store the result in a temporary variable of the required type then pass its pointer as an argument."
I doubt it uses a Variant for this.
If it had been ByVal it would have passed the value instead of creating a temporary and passing a pointer.
To know the details for sure we'd have to compile it and then disassemble the EXE.
-
Nov 18th, 2018, 06:12 PM
#3
Thread Starter
Frenzied Member
Re: Interesting Find - ByRef Mismatch - Integer vs Byte
In terms of correct usage, questions is, would it be better to use:
simpleTest (mBox) or simpleTest cInt(mBox)
_____________________________________________________________________
----If this post has helped you. Please take time to Rate it.
----If you've solved your problem, then please mark it as RESOLVED from Thread Tools.

-
Nov 19th, 2018, 01:38 AM
#4
Re: Interesting Find - ByRef Mismatch - Integer vs Byte
Well, a better question might be why the parameter is declared ByRef instead of ByVal.
I can think of cases where the "Evaluate!" imperative of otherwise-extraneous ( ) is useful, such as when calling an OLE entrypoint that demands ByRef As Variant arguments and you want to pass an Integer or something. Usually though when I see it while reading code it stands out as a mistake.
Even the IDE tries to warn you in a subtle fashion by enforcing a space before the ( character.
I'd probably change it to ByVal and even then use CInt( ) explicitly rather than hope anyone (including me) reading it later catches on to the implicit coercion. However I've failed to do so and thus play "trust the force" often enough myself.
Too bad we have no Option Strict.
-
Nov 19th, 2018, 01:54 AM
#5
Re: Interesting Find - ByRef Mismatch - Integer vs Byte
using () or cint() or anything () will not return correctly. the variable need to be the same type and exact, how else can the function knows where to return?
byref is used to send and/or return while byval only send.
doing a test, where you have a function that do some "math", lets say index As Integer is increased by 1, it will not do anything in mBox if encapsulated.
usually we use () to do some calculation or change type.
sure this shoudn't be possible, most be that the MS didnt think about it.
-
Nov 19th, 2018, 02:42 AM
#6
Re: Interesting Find - ByRef Mismatch - Integer vs Byte
 Originally Posted by some1uk03
I'm assuming that the brackets is changing the variable type to a varient ?
No, the parentheses do not do that. There is this concept of l-value vs r-value you can read up in wikipedia that parentheses (or more generally expressions) affect. In short an l-value is an expression that you can put to the left of an assignement operator (=) and r-value can go in the right-hand part. In A(idx) = 5 * price we have A(idx) an l-value and 5 * price as an r-value.
During compilation each expression is tracked if it's an l-value as this is very simple for the compiler -- an l-value has an *address* where its value is stored during run-time.
If the parameter were declared as ByRef index As Byte your bare mBox expression being of type Byte *and* being an l-value so it has an address that can be passed to the ByRef parameter. Your second (mBox) expression is of type Byte too but does *not* have an address (is not l-value) so the compiler allocates a byte on the stack, stores (mBox) value in this temp byte and passes the address on the stack as actual argument.
The compile-time error you get can be explained with the compiler finding an l-value expression (that has an address) but the type mismatches and it gives up instead of silently creating a temporary on the stack which would be very subversive and introduce subtle bugs when changing local var types on an already working code.
Don't use extraneous parentheses, this is a code-smell IMO. Just be explicit with CInt, CLng and CVar and your future self will thank you while reading this code.
cheers,
</wqw>
-
Nov 19th, 2018, 08:17 AM
#7
Thread Starter
Frenzied Member
Re: Interesting Find - ByRef Mismatch - Integer vs Byte
 Originally Posted by dilettante
Well, a better question might be why the parameter is declared ByRef instead of ByVal.
Assuming we have an array of controls/buttons.
Code:
Private Sub Command1_Click(Index As Integer)
End Sub
and wanted to click x button by passing the mBox variable: Command1_Click mBox
Ideally the Buttons are only a small bunch, so didn't want to make the mBox variable an Integer/wasting memory.
I'll either, use cByte(mBox) to pass the argument or easier to just declare mBox as an Integer i guess.
_____________________________________________________________________
----If this post has helped you. Please take time to Rate it.
----If you've solved your problem, then please mark it as RESOLVED from Thread Tools.

-
Nov 19th, 2018, 08:24 AM
#8
Re: Interesting Find - ByRef Mismatch - Integer vs Byte
For me, I guess there are a few things I think of, and also a good question when I read the OP. For one, I typically let VB6's passed arguments default to ByRef. I do this because it's fewer keystrokes to code, and I also believe that it's possibly ever-so-slightly faster, always pushing four bytes onto the stack as opposed to 8 or more, in the case of Double, Currency, or actual Variants. However, if I want to make sure the arguments don't get changed and the called procedure is too much code to think through to guarantee that, I do use ByVal.
This OP's questions also reminds me that VB6 creates all kinds of temporary variables to get its work done. Trivial often unrecognized examples are when constants or fixed-length strings are passed. These always have a temporary variable created before they are passed.
I also admit that it's my first thought to recommend explicitly using CInt(mBox), rather than implicitly doing whatever (mBox) is doing. Dilettante suggests that, "I doubt it uses a Variant for this", but I wonder. If we use CInt(mBox), we're almost certainly going through a temporary Variant to get our work done. How else do we get the Byte type mBox passed into CInt? The MSDN says CInt(expression) where "The required expression argument is any string expression or numeric expression." Isn't that getting pretty close to the definition of a Variant? Or do we think the compiler is smart enough to parse calls to CInt, based on the argument type, and make calls to separate library routines for each type passed in? I doubt that, as many of VB6 language's functions use similar "expressions" as their arguments, and I doubt they all have a plethora of different entry points in the libraries for the different incoming types. In other words, I suspect, for our temporary variables, we're using Variants much more than we possibly realized.
So, I'll return to the OP's original question, to paraphrase: Should we always use CInt(expression), or is it better to just do implicit type casting with naked parentheses? The more direct questions is, when a procedure is created with an explicit (non-Variant) argument, such as the OP's simpleTest(index As Integer), when we coerce incoming arguments with naked (mBox) parentheses, does VB6 go through a Variant to create the temporary variable? If it doesn't, that's an argument for using the naked parentheses rather than CInt, because it'll be a bit faster. I strongly suspect it does use a Variant. But, I don't have a definite answer to that question. Maybe The Trick will see this and be motivated to take a look.
If naked parentheses do use a Variant to get their work done, then I'd recommend always using CInt(expression) for the clarity. However, if CInt(expression) does use a Variant and naked parentheses don't, that's an argument for using naked parentheses.
Elroy
Last edited by Elroy; Nov 19th, 2018 at 08:42 AM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Nov 19th, 2018, 08:36 AM
#9
Re: Interesting Find - ByRef Mismatch - Integer vs Byte
 Originally Posted by some1uk03
Ideally the Buttons are only a small bunch, so didn't want to make the mBox variable an Integer/wasting memory.
Some1uk03,
I'll give you my two-cents on that one was well. Personally, at that level, I virtually never worried about wasting memory. In fact, when I'm thinking of a mathematical integer, I almost always just create a Long. With various memory boundary enforcements, I suspect Byte, Integer, and Long always take the same amount of memory anyway. Here's a rather trivial test:
Code:
Option Explicit
Private Sub Form_Load()
Dim b1 As Byte
Dim b2 As Byte
MsgBox VarPtr(b1)
MsgBox VarPtr(b2)
End Sub
Be sure to compile it for the test, but watch what you get.
Also, when you always use a Long, you don't run into these ByRef and ByVal problems you presented, and all the associated type casting and temporary variable creation. Therefore, what you've done will actually use more memory and more processing than something like the following:
Code:
Option Explicit
Private Sub simpleTest(index As Long)
MsgBox index, vbOKOnly
End Sub
Private Sub Form_Load()
Dim mBox As Long
simpleTest mBox
End Sub
And I'd be shocked if a Variant is used for anything in the above. (Actually, that's not true. I suspect a temporary Variant will be used to type cast index to a string when the MsgBox is actually called.)
Take Care,
Elroy
Last edited by Elroy; Nov 19th, 2018 at 08:48 AM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Nov 19th, 2018, 10:14 AM
#10
Re: Interesting Find - ByRef Mismatch - Integer vs Byte
 Originally Posted by Elroy
If naked parentheses do use a Variant to get their work done, then I'd recommend always using CInt(expression) for the clarity. However, if CInt(expression) does use a Variant and naked parentheses don't, that's an argument for using naked parentheses.
Both don't create a Variant intermediate, that would be highly ineffective language construct. CInt is not a regular function but a type conversion function and it's even color coded in the IDE as a statement (not regular function).
cheers,
</wqw>
-
Nov 19th, 2018, 11:29 AM
#11
Re: Interesting Find - ByRef Mismatch - Integer vs Byte
 Originally Posted by wqweto
Both don't create a Variant intermediate, that would be highly ineffective language construct. CInt is not a regular function but a type conversion function and it's even color coded in the IDE as a statement (not regular function).
cheers,
</wqw>
But Wqweto, I only see two possibilities for getting data (arguments) into the CInt library function: 1) there are actually separate library entry points for each argument type you may pass to CInt, and the compiler sorts this out; or 2) the argument is passed into CInt in some kind of way that the library can identify what kind of variable it is ... and that's almost the definition of a Variant.
Just saying,
Elroy
EDIT1: Wait, you're saying that the compiler just puts inline code in wherever a CInt is used?
EDIT2: And, if that's true, that's interesting because CInt still works with an explicit Variant argument, where it may not even know the data type it's converting.
Last edited by Elroy; Nov 19th, 2018 at 11:33 AM.
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Nov 19th, 2018, 11:37 AM
#12
Re: Interesting Find - ByRef Mismatch - Integer vs Byte
 Originally Posted by Elroy
EDIT1: Wait, you're saying that the compiler just puts inline code in wherever a CInt is used?
EDIT2: And, if that's true, that's interesting because CInt still works with an explicit Variant argument, where it may not even know the data type it's converting.
This wouldn't be the first time you thought an intrinsic only existed as a function call. 
Remember Len/LenB()?
-
Nov 19th, 2018, 12:04 PM
#13
Re: Interesting Find - ByRef Mismatch - Integer vs Byte
I can't see anything to suggest that event signatures like:
Code:
Private Sub Command1_Click(Index As Integer)
... are anything but an accident or an artifact left over for compatibility with much earlier versions of VB. They most likely exist because in ancient times MS Basic didn't have an ability to pass by value as a language construct.
What would be the meaning of changing Index there? What could it possibly do, click another control? I can assure you that it does not.
About the only time I'll pass something ByRef when the procedure isn't meant to alter its value is When an interface gives you no option as in those event signatures, for an array where you have no option, and a String when I know it won't be marshaled between threads, processes, or machines.
That's right, there are places where ByRef As String is slower than ByVal As String. But I'm probably not telling you anything new since the documentation harps on that in multiple places.
From what I can find the use of dangling ( ) was a sort of feature of ancient Basic, not a bug:
Example 2
Code:
CALL MySUB (a%, (b%), (c%)) 'CALL SUB b and c stay 0 after sub
MySUB a%, b%, (c%) 'call SUB again without CALL only c stays 0 after sub
PRINT "After procedures: "; a%, b%, c%
SUB MySUB (a%, b%, c%)
a% = a% + 1: b% = b% + 1: c% = c% + 1
PRINT "Inside procedure: "; a%, b%, c%
END SUB
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|