Compile Error Expected Function Or Variable - vba

I'm new and trying to learn VBA. When I'm typing in the code I get Compile Error Expected Function Or Variable.
Is something regarding the activecell, but can't figure it out.
Sub Testare()
Dim FilmName As String
Dim FilmLenght As Integer
Dim FilmDescription As String
Range("b10").Select
FilmName = ActiveCell.Value
FilmLenght = ActiveCell.Offset(0, 2).Value
If FilmLenght < 100 Then
FilmDescription = "Interesant"
Else
FilmDescription = "Suficient"
End If
MsgBox FilmName & " is " & FilmDescription
End Sub

This error happens also when a Sub is called the same as variable (i.e. in one Sub you have for loop with iterator "a", whilst another Sub is called "a").
This gives an error that fits to your description.
Regards

It is possible to make your code fail in two different ways:
Place a very large value in D10
Place a text value in D10
This will result in either an overflow error or type mismatch error.

I know this was asked a while ago, but I ended up with the same error when I created a Sub within a worksheet with the Sub Name the same as the Worksheet name.
Unfortunately when this happens, no error is highlighted by a compile; the error only appears at run time. Also, the offending line is not highlighted, which makes it a bit difficult to find.
Changing the Sub name solves it though.

Here is what caused this error in my case:
Inside a new Public Function that I was starting to write, I began to type a statement, but needed to copy a long varname from another location, so I just inserted the letter a to prevent Excel from popping-up the uber-annoying Compile Error: Expected Expression dialog. So I had this:
myVarName = a
I then attempted to step-through my code to get to that point, and when Excel entered that function I received the message "Compile Error: Expected Function Or Variable". To resolve, I just changed the placeholder to a number:
myVarName = 1
And all continued just fine.

Related

Userform throws error when using "." or "-" or "backspace"

Hello my userform in Excel keeps throwing an error whenever I try to input anything that isnt a number i.e. "." or "-" or if I backspace my number to clear the row.
I believe it because I defined the variable that the userform will be assigned to as a long.
This prevents me from inputting negative numbers or decimals without throwing an error.
Any idea's as to how I can allow my userform to accept the Long variable type while still allowing me to enter other characters that aren't directly a number?
To be clear the error occurs while entering the number into the UF not after I action the Userform.
EDIT:
Code for this is quite simple
Public LTB As Long
Public Sub LotTextBox_Change()
LTB = LotTextBox.Value
End Sub
Error Msg is - Run time error 13 - Mismatch.
The problem that you are facing is because you are trying to store whatever is being typed in the textbox which is a String at runtime to a Long Variable.
So if you want to type -123 then the moment you type -, you will get an error as you are trying to store a String i.e - in a Long variable.
Try this
Public LTB As Long
Private Sub LotTextBox_Change()
On Error GoTo Whoa
LTB = Val(LotTextBox.Value)
Whoa:
'Debug.Print LTB
End Sub
What this does is, it tries to store the textbox value to the variable and if it is not of correct datatype, it exits gracefully.

How to make a string accept an Excel error- runtime error 13- mismatch

I am trying to format downloaded data and then insert into SQL. The nature of the data is such that there will be errors such as #NAME?, #N/A Invalid Field etc. I have a variable of data type string which takes the value of a new cell each time a for loop is run. The loop crashes due to a mismatch error occuring when the loop hits a data point with an error in it (found out my message boxing the loop).
Why can a string not accept an error as its value for the string? I have seen a post about this and the recommended answer was to use If IsError but I need the '#N/A' part of the error as to identify that one has occured, rather than skip the row. Any suggestions would be greatly appreciated! Thanks :) An Extract of the code is below:
'Insert static fields
Dim field As String
code = "'" & tbl.DataBodyRange(i, 1) & "'"
For j = 2 To 48
MsgBox (tbl.DataBodyRange(i, j))
field = tbl.DataBodyRange(i, j).Value
'Recursively going through each cell
If InStr(field, "#N") <> 0 Then
field = "NULL "
k = 1
It hits the error at the messagebox first, the message box will display the mismatch error.
One way around the problem is to use the VARIANT data type to deal with the error.
As you've found out a STRING variable can't hold an error value, while the VARIANT can. You can then use code along the lines of:
IF ISERROR(field) THEN
field = NULL
K=1
END IF
A VARIANT can also hold a NULL value.
Edit:
I have seen a post about this and the recommended answer was to use
If IsError but I need the '#N/A' part of the error as to identify that
one has occured, rather than skip the row.
The ISERROR part identifies that an error has occurred. This line of code on its own won't skip the row; it gives you an opportunity to do something else with the row such as replace the error value with a NULL value or some other required value.

How do I pass a range obj variable to a sub in Excel VBA (2016) [duplicate]

This question already has an answer here:
Array argument must be ByRef
(1 answer)
Closed 6 years ago.
Given the following code:
I can not seem to successfully pass a Range Object Variable from one sub-function to another. I spent an entire day researching, and experimenting before I swallowed pride and came here.
Please read the comments below, and reply with any ideas you have regarding why the LAST two lines will not behave.
Public Sub doSomethingToRows(ROI As Range)
*'do Something with the cell values within the supplied range*
End Sub
'
Public Sub testDoAltRows()
Dim RegionOfInterest As Range 'is this an object or not?
'*The following yields: Class doesn't support Automation (Error 430)*
'*Set RegionOfInterest = New Worksheet 'this just gives an error*
Set RegionOfInterest = Worksheets("Sheet1").Range("A1")
RegionOfInterest.Value = 1234.56 '*okay, updates cell A1*
Set RegionOfInterest = Worksheets("Sheet1").Range("B5:D15")
RegionOfInterest.Columns(2).Value = "~~~~~~" '*okay*
'doSomethingToRows (RegionOfInterest) 'why do I get "OBJECT IS REQUIRED" error?
doSomethingToRows (Worksheets("Sheet1").Range("B5:C15")) 'but this executes okay
End Sub
From the msdn documentation of the Call keyword statement,
Remarks
You are not required to use the Call keyword when calling a procedure.
However, if you use the Call keyword to call a procedure that requires
arguments, argumentlist must be enclosed in parentheses. If you omit
the Call keyword, you also must omit the parentheses around
argumentlist. If you use either Call syntax to call any intrinsic or
user-defined function, the function's return value is discarded.
To pass a whole array to a procedure, use the array name followed by
empty parentheses.
From a practical standpoint, even though Subs can be called with or without the "Call" keyword, it makes sense to pick one way and stick with it as part of your coding style. I agree with Comintern - it is my opinion, based on observation of modern VBA code, that using the "Call" keyword should be considered deprecated. Instead, invoke Subs without parenthesis around the argument list.
And now the answer to the important question:
Why does your code throw an error?
Take for example the following Subroutine:
Public Sub ShowSum(arg1 As Long, arg2 As Long)
MsgBox arg1 + arg2
End Sub
We have established that, if not using the Call keyword, Subs must be invoked like so:
ShowSum 45, 37
What happens if it were instead called like ShowSum(45, 37)? Well, you wouldn't even be able to compile as VBA immediately complains "Expected =". This is because the VBA parser sees the parenthesis and decides that this must be a Function call, and it therefore expects you to be handling the return value with an "=" assignment statement.
What about a Sub with only one argument? For example:
Public Sub ShowNum(arg1 As Long)
MsgBox arg1
End Sub
The correct way to call this Sub is ShowNum 45. But what if you typed this into the VBA IDE: ShowNum(45)? As soon as you move the cursor off of the line, you'll notice that VBA adds a space between the Sub name and the opening parenthesis, giving you a crucial clue as to how the line of code is actually being interpreted:
ShowNum (45)
VBA is not treating those parenthesis as if they surrounded the argument list - it is instead treating them as grouping parenthesis. MOST of the time, this wouldn't matter, but it does in the case of Objects which have a default member.
To see the problem this causes, try running the following:
Dim v As Variant
Set v = Range("A1")
Set v = (Range("A1")) '<--- type mismatch here
Notice that you get a "Type Mismatch" on the marked line. Now add those two statements to the watch window and look at the "Type" column:
+-------------+-----+--------------+
| Expression |Value| Type |
+-------------+-----+--------------+
|Range("A1") | |Object/Range |
|(Range("A1"))| |Variant/String|
+-------------+-----+--------------+
When you surround an Object with grouping parenthesis, its default property is evaluated - in the case of the Range object, it is the Value property.
So it's really just a coincidence that VBA allowed you to get away with "putting parenthesis around the argumentlist" - really, VBA just interprets this as grouping parenthesis and evaluates the value accordingly. You can see by trying the same thing on a Sub with multiple parameters that it is invalid in VBA to invoke a Sub with parenthesis around the argument list.
#PaulG
Try this:
Public Sub Main()
Debug.Print TypeName(Range("A1"))
Debug.Print TypeName((Range("A1")))
End Sub
okay, I knew after I posted this question I'd be struck by lighting and receive an answer.
When passing an object VARIABLE to a sub-function and wishing to use parentheses "()", one must use CALL! Thus the correction to my code sample is:
**CALL doSomethingToRows(RegionOfInterest)**
Thank you!
Maybe we're talking about different things, but here's an example to make it a bit clearer what I mean.
Option Explicit
Sub TestDisplay()
Dim r As Range
'Create some range object
Set r = Range("A1")
'Invoke with Call.
Call DisplaySomething(r)
'Invoke without Call.
DisplaySomething r
End Sub
Sub DisplaySomething(ByVal Data As Range)
Debug.Print "Hi my type is " & TypeName(Data)
End Sub
Both calls work perfectly. One with Call and the other without.
Edit:
#Conintern. Thanks for explaining that. I see what is meant now.
However, I still respectively disagree.
If I declare the following:
Function DisplaySomething(ByVal Data As String)
DisplaySomething = "Hi my type is " & TypeName(Data)
End Function
and invoke it:
Debug.print DisplaySomething(Range("A1"))
I believe that Excel has been clever and converted to a string. It can do that by invoking the Default Parameter and can convert to a string.
However, as in the original parameter example, If I declare the following:
Function DisplaySomething(ByVal Data As Range)
DisplaySomething = "Hi my type is " & TypeName(Data)
End Function
There is no call on the Default Parameter, however it is called, because Excel was able to resolve it to that type.
Function DisplaySomething(ByVal Data As Double)
DisplaySomething = "Hi my type is " & TypeName(Data)
End Function
will return a double because it was able to coerce to a double.
Indeed in those examples the Default was called.
But in this example we are defining as Range. No Default called there however it is invoked - brackets or no brackets.
I believe this is more to do with Excel and data coercion.
Similar to the following:
Public Function Test(ByVal i As String) As Integer
Test = i
End Function
and invoking with:
Debug.print Test("1")
BTW, yes I know this isn't an object without a Default parmeter. Im pointing out data coercion. Excel does its best to resolve it.
Could be wrong mind you...

Why does my comparator not work after first loop?

I have a pretty simple If Else statement in my code that looks like this:
If GUI.editedFH = "" Then
fhNumField.Value = fhNumField.List(0)
Else
fhNumField.Value = editedFH
End If
This block of code is in a UserForm_Initialize() sub that I call fairly often after users use the form to edit or delete rows of data. I unload the form and reload it as a way to "refresh" the data presented in the form.
The code fails at the first line in that If statement. VBE throws this error
Run-time error '1004':
Application-defined or object-defined error
GUI.editedFH is a global string that is declared in a separate module. GUI is the name of the module, and editedFH is the string variable name. I put a watch on GUI.editedFH and I'm getting String as the type and the value that I want.
When I hardcode string values in, instead of GUI.editedFH, it still doesn't work i.e.
If "abc" = "" Then
'....
End If
The part that is most confusing is that I can compare strings like this elsewhere, and it is seemingly random on when the error will throw. It will work the first time through the initialize and a few subsequent times, but eventually it will throw an error.

VBA UDF fails to call Range.Precedents property

I am trying to write a simple UDF, which is supposed to loop through each of the cells of a given_row, and pick up those cells which do not have any precedent ranges, and add up the values.
Here is the code:
Public Function TotalActualDeductions(given_row As Integer) As Integer
Total_Actual_Deduction = 0
For present_column = 4 To 153
Set precedent_range = Nothing
If Cells(2, present_column) = "TDS (Replace computed figure when actually deducted)" Then
On Error Resume Next
Set precedent_range = Cells(given_row, present_column).Precedents
If precedent_range Is Nothing Then
Total_Actual_Deduction = Total_Actual_Deduction + Cells(given_row, present_column)
End If
End If
Next
TotalActualDeductions = Total_Actual_Deduction
End Function
If I try to run it by modifying the top declaration, from:
Public Function TotalActualDeductions(given_row As Integer) As Integer
to:
Public Function TotalActualDeductions()
given_row = 4
then it runs successfully, and as expected. It picks up exactly those cells which match the criteria, and all is good.
However, when I try to run this as a proper UDF from the worksheet, it does not work. Apparently, excel treats those cells which have no precedents, as though they have precedents, when I call the function from the worksheet.
I don't know why this happens, or if the range.precedents property is supposed to behave like this.
How can this be fixed?
After a lot of searching, I encountered this:
When called from an Excel VBA UDF, Range.Precedents returns the range and not its precedents. Is there a workaround?
Apparently, "any call to .Precedents in a call stack that includes a UDF gets handled differntly".
So, what I did was use Range.Formula Like "=[a-zA-Z]" , because it satisfied my simple purpose. It is in no way an ideal alternative to the range.precedents property.
Foe a more detailed explanation, please visit that link.