I have a 'end if without block if' in visual basic when it compiles - vb6

I am having a problem when I compile my .exe file is says this is the source of the fault. Can anyone recreate this code for me?
Private Sub tmrCounter_Timer()
cntCounter = cntCounter + 1
tmrLogger.Enabled = False
SendCurrentInfos
cntCounter = 0
tmrCounter.Enabled = False
End If
End Sub

I doubt you need an If. You probably just need to remove the end if.
However you may need an If as you are incrementing a counter at top of the procedure, and later set it to 0.

my guess is that the last 3 lines inside the sub should be:
if cntCounter = 0
tmrCounter.Enabled = False
End If
it all depends on the value of cntCounter though, as it always increases in value it should be negative at the start to arrive at 0 at some time, or be altered somewhere else in your code

Related

Skipping an iteration in a for loop in CATScript [duplicate]

A colleague and I were trying to figure out a way of doing the equivalent of a "continue" statement within a VBScript "For/Next" loop.
Everywhere we looked we found people had no way to do this in VBScript without having nasty nestings, which is not an option for us since it is a quite big loop.
We came out with this idea. Would it work just as a "continue(to next iteration)"? Does anyone have any better workaround or improvement suggestion?
For i=1 to N
For workaroundloop = 1 to 1
[Code]
If Condition1 Then
Exit For
End If
[MoreCode]
If Condition2 Then
Exit For
End If
[MoreCode]
If Condition2 Then
Exit For
End If
[...]
Next
Next
Thanks for your comments
Your suggestion would work, but using a Do loop might be a little more readable.
This is actually an idiom in C - instead of using a goto, you can have a do { } while (0) loop with a break statement if you want to bail out of the construct early.
Dim i
For i = 0 To 10
Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False
Next
As crush suggests, it looks a little better if you remove the extra indentation level.
Dim i
For i = 0 To 10: Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False: Next
A solution I decided on involved the use of a boolean variable to track if the for loop should process its instructions or skip to the next iteration:
Dim continue
For Each item In collection
continue = True
If condition1 Then continue = False End If
If continue Then
'Do work
End If
Next
I found the nested loop solutions to be somewhat confusing readability wise. This method also has its own pitfalls since the loop doesn't immediately skip to the next iteration after encountering continue. It would be possible for a later condition to reverse the state of continue. It also has a secondary construct within the initial loop, and requires the declaration of an extra var.
Oh, VBScript...sigh.
Also, if you want to use the accepted answer, which isn't too bad readability wise, you could couple that with the use of : to merge the two loops into what appears to be one:
Dim i
For i = 0 To 10 : Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False : Next
I found it useful to eliminate the extra level of indentation.
One option would be to put all the code in the loop inside a Sub and then just return from that Sub when you want to "continue".
Not perfect, but I think it would be less confusing that the extra loop.
I use to use the Do, Loop a lot but I have started using a Sub or a Function that I could exit out of instead. It just seemed cleaner to me. If any variables you need are not global you will need to pass them to the Sub also.
For i=1 to N
DoWork i
Next
Sub DoWork(i)
[Code]
If Condition1 Then
Exit Sub
End If
[MoreCode]
If Condition2 Then
Exit Sub
End If
[MoreCode]
If Condition2 Then
Exit Sub
End If
[...]
End Sub
We can use a separate function for performing a continue statement work. suppose you have following problem:
for i=1 to 10
if(condition) then 'for loop body'
contionue
End If
Next
Here we will use a function call for for loop body:
for i=1 to 10
Call loopbody()
next
function loopbody()
if(condition) then 'for loop body'
Exit Function
End If
End Function
loop will continue for function exit statement....
I've always used an Do While loop. This works with both For type loops.
For iIndex = 0 to 100
Do
If bCondition then Exit Do
...
Loop While False
Next
IMHO, this just looks clean.
I just saw Crush's answer, at the bottom. Sorry for the duplicate answer.
Implement the iteration as a recursive function.
Function Iterate( i , N )
If i == N Then
Exit Function
End If
[Code]
If Condition1 Then
Call Iterate( i+1, N );
Exit Function
End If
[Code]
If Condition2 Then
Call Iterate( i+1, N );
Exit Function
End If
Call Iterate( i+1, N );
End Function
Start with a call to Iterate( 1, N )
Try use While/Wend and Do While / Loop statements...
i = 1
While i < N + 1
Do While true
[Code]
If Condition1 Then
Exit Do
End If
[MoreCode]
If Condition2 Then
Exit Do
End If
[...]
Exit Do
Loop
Wend
I think you are intended to contain ALL YOUR LOGIC under your if statement. Basically:
' PRINTS EVERYTHING EXCEPT 4
For i = 0 To 10
' you want to say
' If i = 4 CONTINUE but VBScript has no continue
If i <> 4 Then ' just invert the logic
WSH.Echo( i )
End If
Next
This can make the code a bit longer, but some people don't like break or continue anyway.

Increment Number but skip the first time Ruby

I need to set a loop that increments a variable but doesn't do it the first time around. This is the code, I know I'm close so I'm hoping for some guidance.
offset = 0
while do
if offset = 0
nil
else
offset += 1
end
end
There are a number of issues with your attempt. First of all, your statement if offset = 0 isn't checking if offset equals zero, it's setting it to zero. To check for equality, use ==:
Secondly, even if you fix the first issue, the else of your condition will never fire, because offset will always be zero and therefore never incremented.
Third, if you have nothing to do in an if block, you don't need to put nil, just skip directly to the else:
if offset == 0
else
offset += 1
end
Even better, just negate the expression and skip the else entirely:
if offset != 0
offset += 1
end
Also, while do isn't a valid Ruby construct. You can either write something like while true do or use loop do.
More generally speaking, if you need to execute some code before the offset is incremented, just put that code before the offset is incremented:
offset = 0
loop do
# your code goes here
offset += 1
end
And here's a more "Ruby-ish" way to do it:
0.step do |offset|
# your code goes here
end
Hope this helps.
offset = 0
first_loop = true
loop do
offset += 1 unless first_loop
code here
first_loop = false
end

Ruby Search Array And Replace String

My question is, how can I search through an array and replace the string at the current index of the search without knowing what the indexed array string contains?
The code below will search through an ajax file hosted on the internet, it will find the inventory, go through each weapon in my inventory, adding the ID to a string (so I can check if that weapon has been checked before). Then it will add another value after that of the amount of times it occurs in the inventory, then after I have check all weapon in the inventory, it will go through the all of the IDs added to the string and display them along with the number (amount of occurrences). This is so I know how many of each weapon I have.
This is an example of what I have:
strList = ""
inventory.each do |inv|
amount = 1
exists = false
ids = strList.split(',')
ids.each do |ind|
if (inv['id'] == ind.split('/').first) then
exists = true
amount = ind.split('/').first.to_i
amount += 1
ind = "#{inv['id']}/#{amount.to_s}" # This doesn't seem work as expected.
end
end
if (exists == true) then
ids.push("#{inv['id']}/#{amount.to_s}")
strList = ids.join(",")
end
end
strList.split(",").each do |item|
puts "#{item.split('/').first} (#{item.split('/').last})"
end
Here is an idea of what code I expected (pseudo-code):
inventory = get_inventory()
drawn_inv = ""
loop.inventory do |inv|
if (inv['id'].occurred_before?)
inv['id'].count += 1
end
end loop
loop.inventory do |inv|
drawn_inv.add(inv['id'] + "/" + inv['id'].count)
end loop
loop.drawn_inv do |inv|
puts "#{inv}"
end loop
Any help on how to replace that line is appreciated!
EDIT: Sorry for not requiring more information on my code. I skipped the less important part at the bottom of the code and displayed commented code instead of actual code, I'll add that now.
EDIT #2: I'll update my description of what it does and what I'm expecting as a result.
EDIT #3: Added pseudo-code.
Thanks in advance,
SteTrezla
You want #each_with_index: http://ruby-doc.org/core-2.2.0/Enumerable.html#method-i-each_with_index
You may also want to look at #gsub since it takes a block. You may not need to split this string into an array at all. Basically something like strList.gsub(...){ |match| #...your block }

Is there a better way to write the following VB6 snippet?

I work at $COMPANY and I'm helping maintain $LEGACY_APPLICATION. It's written in visual basic 6.
I was faced with doing an unpleasantly elaborate nested if statement due to the lack of VB6's ability to perform short circuit evaluations in if statements (which would simplify this a lot). I've tried AndAlso, but to no avail. Must be a feature added after VB6.
Some genius on SO somewhere pointed out that you can trick a select case statement into working like a short-circuiting if statement if you have the patience, so I tried that, and here's what I came up with:
Select Case (True) ' pretend this is an if-else statement
Case (item Is Nothing): Exit Sub ' we got a non-element
Case ((item Is Not Nothing) And (lastSelected Is Nothing)): Set lastSelected = item ' we got our first good element
Case (item = lastSelected): Exit Sub ' we already had what we got
Case (Not item = lastSelected): Set lastSelected = item ' we got something new
End Select
It's definitely a little unusual, and I had to make use of my fantastic whiteboard (which, by the way, is pretty much the most useful programming resource besides a computer) to make sure I had mapped all of the statements correctly.
Here's what's going on there: I have an expensive operation which I would like to avoid repeating if possible. lastSelected is a persistent reference to the value most recently passed to this calculation. item is the parameter that was just received from the GUI. If there has never been a call to the program before, lastSelected starts out as Nothing. item can be Nothing too. Additionally, if both lastSelected and item are the same something, skip the calculation.
If I were writing this in C++, I would write:
if (item == NULL || (lastSelected != NULL && item->operator==(*lastSelected))) return;
else lastSelected = item;
However, I'm not.
Question
How can I rewrite this to look better and make more sense? Upvotes will be awarded to answers that say either "YES and here's why: X, Y, Z" or "NO, and here's why not: X, Y, Z".
Edits
Fixed the C++ statement to match the VB6 one (they were supposed to be equivalent)
This is shorter and 100x more readable.
EDIT Wug edited the code in MarkJ's original answer, into this:
If (item Is Nothing)
Then Exit Sub ' we got a non-element
ElseIf (lastSelected Is Nothing) Then
Set lastSelected = item ' we got our first go
ElseIf (item = lastSelected) Then
Exit Sub ' we already had what we got
End If
Set lastSelected = item ' we got something new
Here's MarkJ's edit in response. One nested if, but only one Set. Seems neater to me.
If (item Is Nothing) Then
Exit Sub ' we got a non-element
ElseIf Not (lastSelected Is Nothing) Then ' not our first go
If (item = lastSelected) Then
Exit Sub ' we already had what we got
End If
End If
Set lastSelected = item ' we got something new
' does stuff here? #Wug is that true?
To compare reference equality in VB6 use item Is LastSelected. Because item = lastSelected will probably evaluate the default properties in the objects and compare those instead!
Since brevity appears to be a goal, consider this. If you Exit Sub when condition X is True, you don't need to check X again later. It is False! Unless it changes its value in between evaluations (e.g. X is a function that checks the system clock). You were checking whether item was lastSelected, then whether it wasn't. And if item Is Nothing is False, do not bother to check whether item Is Not Nothing is True!
VB6 does not short circuit for backwards compatibility with ancient versions of Basic
Stop worrying that VB6 is not some other language and relax!
YES
I translated it from your case statement. I find it easier to read, personally.
If Item Is Nothing Then
Exit Sub ' we got a non-element
ElseIf LastSelected Is Nothing Then
Set LastSelected = Item ' we got our first good element
ElseIf Item = LastSelectedItem Then
Exit Sub ' we already had what we got
Else
Set LastSelected = Item ' we got something new
End If
You asked for explanation. I tried not to have to give much (by re-using your own code comments).
But here it is anyway :-)
Firstly if there is no item, just exit. Easy.
Otherwise if LastSelected Is Nothing then we know, because the first if condition failed, that Item exists, and it's safe to mark that value as having been Last Selected. As you say, we got our first good element. The sub continues on.
However if we have existing values for Item and LastSelected, then either they are equal or not. If they are equal, just quit.
If they aren't equal, then update LastSelected. As you say, we got something new.
You can use a helper function like this:
Private Function pvGetItemData(oItem As ListItem) As Variant
If Not oItem Is Nothing Then
pvGetItemData = oItem.Tag
Else
pvGetItemData = -1
End If
End Function
and then
If pvGetItemData(Item) = pvGetItemData(LastSelected) Then
' cache hit
Else
' do calc
Set LastSelected = Item
End If
YES
I'd make that simpler:
If item Is Nothing Then
Exit Sub ' we got a non-element
Else
Set lastSelected = item ' we got something to assign
End If
Unless there are side effects assigning lastItem (it can be property with invalid assignment code), then code logic is essentially same.
If you are not required to exit the sub (snippet is at the end of sub or something), then next is even simpler:
If Not (item Is Nothing) Then Set lastSelected = item
BTW, your Select Case (True) looks really odd to VB programmer :)

"Continue" (to next iteration) on VBScript

A colleague and I were trying to figure out a way of doing the equivalent of a "continue" statement within a VBScript "For/Next" loop.
Everywhere we looked we found people had no way to do this in VBScript without having nasty nestings, which is not an option for us since it is a quite big loop.
We came out with this idea. Would it work just as a "continue(to next iteration)"? Does anyone have any better workaround or improvement suggestion?
For i=1 to N
For workaroundloop = 1 to 1
[Code]
If Condition1 Then
Exit For
End If
[MoreCode]
If Condition2 Then
Exit For
End If
[MoreCode]
If Condition2 Then
Exit For
End If
[...]
Next
Next
Thanks for your comments
Your suggestion would work, but using a Do loop might be a little more readable.
This is actually an idiom in C - instead of using a goto, you can have a do { } while (0) loop with a break statement if you want to bail out of the construct early.
Dim i
For i = 0 To 10
Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False
Next
As crush suggests, it looks a little better if you remove the extra indentation level.
Dim i
For i = 0 To 10: Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False: Next
A solution I decided on involved the use of a boolean variable to track if the for loop should process its instructions or skip to the next iteration:
Dim continue
For Each item In collection
continue = True
If condition1 Then continue = False End If
If continue Then
'Do work
End If
Next
I found the nested loop solutions to be somewhat confusing readability wise. This method also has its own pitfalls since the loop doesn't immediately skip to the next iteration after encountering continue. It would be possible for a later condition to reverse the state of continue. It also has a secondary construct within the initial loop, and requires the declaration of an extra var.
Oh, VBScript...sigh.
Also, if you want to use the accepted answer, which isn't too bad readability wise, you could couple that with the use of : to merge the two loops into what appears to be one:
Dim i
For i = 0 To 10 : Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False : Next
I found it useful to eliminate the extra level of indentation.
One option would be to put all the code in the loop inside a Sub and then just return from that Sub when you want to "continue".
Not perfect, but I think it would be less confusing that the extra loop.
I use to use the Do, Loop a lot but I have started using a Sub or a Function that I could exit out of instead. It just seemed cleaner to me. If any variables you need are not global you will need to pass them to the Sub also.
For i=1 to N
DoWork i
Next
Sub DoWork(i)
[Code]
If Condition1 Then
Exit Sub
End If
[MoreCode]
If Condition2 Then
Exit Sub
End If
[MoreCode]
If Condition2 Then
Exit Sub
End If
[...]
End Sub
We can use a separate function for performing a continue statement work. suppose you have following problem:
for i=1 to 10
if(condition) then 'for loop body'
contionue
End If
Next
Here we will use a function call for for loop body:
for i=1 to 10
Call loopbody()
next
function loopbody()
if(condition) then 'for loop body'
Exit Function
End If
End Function
loop will continue for function exit statement....
I've always used an Do While loop. This works with both For type loops.
For iIndex = 0 to 100
Do
If bCondition then Exit Do
...
Loop While False
Next
IMHO, this just looks clean.
I just saw Crush's answer, at the bottom. Sorry for the duplicate answer.
Implement the iteration as a recursive function.
Function Iterate( i , N )
If i == N Then
Exit Function
End If
[Code]
If Condition1 Then
Call Iterate( i+1, N );
Exit Function
End If
[Code]
If Condition2 Then
Call Iterate( i+1, N );
Exit Function
End If
Call Iterate( i+1, N );
End Function
Start with a call to Iterate( 1, N )
Try use While/Wend and Do While / Loop statements...
i = 1
While i < N + 1
Do While true
[Code]
If Condition1 Then
Exit Do
End If
[MoreCode]
If Condition2 Then
Exit Do
End If
[...]
Exit Do
Loop
Wend
I think you are intended to contain ALL YOUR LOGIC under your if statement. Basically:
' PRINTS EVERYTHING EXCEPT 4
For i = 0 To 10
' you want to say
' If i = 4 CONTINUE but VBScript has no continue
If i <> 4 Then ' just invert the logic
WSH.Echo( i )
End If
Next
This can make the code a bit longer, but some people don't like break or continue anyway.

Resources