x
This website is using cookies. We use cookies to ensure that we give you the best experience on our website. More info. That's Fine
HPC:Factor Logo 
 
Latest Forum Activity

eVB - left() returns "object not a collection, but right() doesn't

I dunk for bananas Page Icon Posted 2024-01-13 11:48 AM
#
Avatar image of I dunk for bananas
H/PC Elite

Posts:
701
Location:
Europe
Status:
For the program I'm writing, I need to isolate the first two characters of a string, so I'm trying to use Left() to do so.
This is what I'm trying to do:

MsgBox (Left("test", 1))
This returns "Object not a collection".

MsgBox (Right("test", 1))

This code, on the other hand, returns "t".

How is this possible? Is there another way I can isolate the first two characters of my string?

edit:
MsgBox (Mid("test", 1, 2))
works. I guess it's just a bug within eVB itself?

Edited by I dunk for bananas 2024-01-13 11:55 AM
 Top of the page
C:Amie Page Icon Posted 2024-01-13 1:39 PM
#
Avatar image of C:Amie
Administrator
H/PC Oracle

Posts:
17,970
Location:
United Kingdom
Status:
Mid is slower than Left() so if you are iterating this, you might want to try and fix this.

Couple of things springs to check:

Are you using Option Explicit? If not add Option Explicit (project menu > Properties > Compile > Set Option Explicit to On)

Are you 100% certain that the line number in the exception was the line number for MsgBox (Left("test", 1))

Is collection error coming from Left or from MsgBox

This will trap the correct line number and ascertain if it is left or msgbox - or if it is a string literal error, accidental use of non-ASCII quotation marks:
Dim str1 as String 
Dim str2 as String  
str1 = "test"
str2 = Left(str1, 1)
msgbox(str2)
 Top of the page
WinCEDev Page Icon Posted 2024-01-13 4:26 PM
#
Avatar image of WinCEDev
Factorite (Senior)

Posts:
75
Location:
Europe
Status:
Unfortunately this is a bug in eVB, it is interpreting "Left" as a property of the form (e.g. Me.Left) instead of the string manipulation function. This only happens with code inside forms, Left works fine from a module.

You've already found the best way to work around it which is to use Mid, or alternatively you could move the affected code to a module.

Microsoft used to have a KB article about this: Q180455.

As an aside, eVB is throwing the rather confusing "Object not a collection" error because the value of Left (the property) is a number. VB interprets the parentheses as trying to access an array index, but the value isn't an array or a type of collection object.

Once I have some time I'll collect all the eVB issues I know about and make a post about it, fortunately most of them can be worked around.
 Top of the page
C:Amie Page Icon Posted 2024-01-13 4:35 PM
#
Avatar image of C:Amie
Administrator
H/PC Oracle

Posts:
17,970
Location:
United Kingdom
Status:
Yikes Microsoft, that's beautiful....
 Top of the page
PhMajerus Page Icon Posted 2024-03-09 12:17 AM
#
Avatar image of PhMajerus
H/PC Newbie

Posts:
9
Location:
Switzerland 
Status:
Be careful with eVB's calling syntax.
Unlike VB.net, classic VB (such as VB6, VBA, VBScript) does not take parenthesis around procedures and methods that are used like procedures (without using a return value, regardless of whether they return one or not). Only functions and procedures which are used like functions (using their return value) use parentheses.

But it works with the parenthesis you might say...
Yes, in this specific example it works because while the parenthesis have another purpose, the end result here is the same.

Here's the story, parenthesis around an argument turn it into an expression, making it behave similarly to a ByVal instead of a ByRef, meaning you're passing the value of the argument using a temporary variable, instead of a reference to that argument.
Most procedures and methods will give you the same result, but it can change the behavior.

Imagine you write the following procedure:
Sub Inc(A): A=A+1: End Sub

Now if you execute the following code:
A = 1
Inc A
MsgBox A
You'll get 2, because the procedure received the A variable by reference, incremented its value, and stored the new value in that variable.

However, if you execute the following code:
A = 1
Inc (A)
MsgBox A
You'll get 1, because A was evaluated to the value 1, which was stored in a temporary variable and passed to the procedure, which incremented it, but the temporary variable then got discarded, and A never changed.

This also means you'll get weird errors if you don't know what's going on:
MsgBox "Hello" ' Works.
MsgBox ("Hello") ' Works as well.
MsgBox ("Hello",1) ' doesn't work, "Cannot use parentheses when calling a Sub" error.
MsgBox "Hello",1 ' Works, using ok/cancel buttons instead of ok.
MsgBox ("Hello"),(1) ' Also works, passing both as ByVal-like.

The only calling syntax that supports parenthesis around a procedure's arguments is using the legacy Call keyword:
Call MsgBox ("Hello", 1)


Edited by PhMajerus 2024-03-09 12:17 AM
 Top of the page
PhMajerus Page Icon Posted 2024-03-09 12:22 AM
#
Avatar image of PhMajerus
H/PC Newbie

Posts:
9
Location:
Switzerland 
Status:
Oh, and about that Left function being shadowed by the Left method of a form so you cannot use it in a form's code.

Create a module you name Str, and put the following function in that module:
Public Function L (S, C): L = Left(S, C): End Function

Now you can call Str.L instead of Left from within form modules, and benefit from the performance of the native Left function.
This indirection trick can be used to regain access to any shadowed function or procedure. You only lose the ability to support variable number of arguments that some native functions/procs have.

Edited by PhMajerus 2024-03-09 12:25 AM
 Top of the page
Jump to forum:
Seconds to generate: 0.157 - Cached queries : 43 - Executed queries : 30