Question

VBA type mismatch error in custom data structure

Asked by: alainbryden

Hey. I've created a custom data structure that is supposed to be able to store anything. It uses a collection.

When inserting an item, I used the following:
Private main As New Collection
Public Sub Add(ByRef obj As Variant, ....)
...
main.Add obj, "key"


When retrieving the item, I try to use the following:
Public Function Item(...) As Variant
    Set Item = main.Item("key")


This works fine if I am storing a set of objects in my data structure, but as soon as I try to store something like a String, the line "Set Item = ...." fails.

This appears to be because (main.Item("key")) resolves to a "Variant/String" and VBA will not let me use the "Set" keyword on a string.

By removing "Set" the data structure works for strings, but no longer works for objects - I get "object variable or with block variable not set".


How can I design my data structure so that it will work on any type, objects, strings, arrays, etc? The native VBA Collection seems to able to do it, why can't I?

This Question has been solved and asker verified All Experts Exchange premium technology solutions are available to subscription members.

Subscribe now for full access to Experts Exchange and get

Instant Access to this Solution

  • Plus...
  • 30 Day FREE access, no risk, no obligation
  • Collaborate with the world's top tech experts
  • Unlimited access to our exclusive solution database
  • Never be left without tech help again

Subscribe Now

Asked On
2009-11-04 at 10:10:29ID24871833
Topics

Visual Basic Programming

,

Microsoft Excel Spreadsheet Software

,

Microsoft Access Database

Participating Experts
4
Points
500
Comments
19

Trusted by hundreds of thousands everyday for fast, accurate and reliable tech support.

  • "The time we save is the biggest benefit of Experts Exchange to Warner Bros. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange." Mike Kapnisakis, Warner Bros.
  • "Our team likes having a resource that is more secure than just using Google and most experts using this service really know their stuff. It's nice to look here first versus using Google." Dayna Sellner, Lockheed Martin
  • "Anytime that I've been stumped with a problem, 9 out of 10 times Experts Exchange has either the accepted solution or an open discussion of the potential solution to the problem." Kenny Red, eBay Inc.

See what Experts Exchange can do for you.

Got a question?

We've got the answer.

Experts Exchange has been collecting answers to technology questions since 1996…3 million and counting! If you have a question, chances are we already have your answer.

Screenshot of Experts Exchange Knowledgebase

Need individual assistance?

Our experts are ready to help.

If you can't find the exact answer you're looking for, ask our exclusive community of 50,000 experts. You’ll get a personalized answer from a trusted professional.

Screenshot of Experts Exchange Knowledgebase

Want to learn from the best?

Read articles from industry experts.

Thousands of free tech tips, tricks, how-to’s and tutorials are available in our peer reviewed articles section. See for yourself how smart our experts are, no login required.

Screenshot of an Article

Working on a long term project?

Store your work and research.

Save solutions to your questions, answers you’ve discovered through searching plus helpful articles in your personal knowledgebase for easy future access.

Screenshot of Experts Exchange Knowledgebase

Access the answers to your technology questions today.

Subscribe Now

30-day free trial. Register in 60 seconds.

What Makes Experts Exchange Unique?

Members of the expert community talk about why the experience at Experts Exchange is different than what you will find anywhere else.

Trusted by the world's most respected brands.

image of each brand's logo

Faithfully serving IT professionals since 1996.

Experts Exchange Logo

Try it out and discover for yourself.

Subscribe Now

30-day free trial. Register in 60 seconds.

Related Solutions

  1. ByRef argument Type mismatch ??
    Beginner question... I'm not sure what I'm doing wrong here. 'have sub to print contents of range (mostly debug code) sub printRange(name as String, rng as Range) ' ... some code ... end sub 'So this works: printRange("foo", Range("foo)) 'And this does...
  2. Better way to test iserror(obj)   and how to set obj = err
    I am looking for an elegant solution to a problem. It is unimportant, but pretty difficult and subtle, so only work on it if you like weird questions. I have a subroutine that sometimes detects an error. I want my program to record this fact in a variable for later action....

Free Tech Articles

  1. WARNING: 5 Reasons why you should NEVER fix a computer for free.
    It is in our nature to love the puzzle. We are obsessed. The lot of us. We love puzzles. We love the challenge. We thrive on finding the answer. We hate disarray. It bothers us deep in our soul. W...
  2. SCCM OSD Basic troubleshooting
    SCCM 2007 OSD is a fantastic way to deploy operating systems, however, like most things SCCM issues can sometimes be difficult to resolve due to the sheer volume of logs to sift through and the dispe...
  3. Migrate Small Business Server 2003 to Exchange 2010 and Windows 2008 R2
    This guide is intended to provide step by step instructions on how to migrate from Small Business Server 2003 to Windows 2008 R2 with Exchange 2010. For this migration to work you will need the fo...
  4. Create a Win7 Gadget
    This article shows you how to create a simple "Gadget" -- a sort of mini-application supported by Windows 7 and Vista. Gadgets can be dropped anywhere on the desktop to provide instant information, ...
  5. Outlook continually prompting for username and password
    There have been a lot of questions recently regarding Outlook prompting for a username and password whilst using Exchange 2007. There are a few reasons why this would happen and I will try to cover t...
  6. Backup Exchange 2010 Information Store using Windows Backup
    There seems to be quite a lot of confusion around the ability to backup Exchange 2010 using the built in Windows Backup feature. This stems from the omission of this feature prior to Exchange 2007 s...

Cloud Class Webinars

  1. Avoiding Bugs in Microsoft Access
    Alison Balter takes and in-depth look at avoiding bugs in Access. In this webinar you will learn about using the immediate window to debug your applications, invoking the debugger, using breakpoints to troubleshoot, stepping through code, setting the next statement to execute, ...
  2. Top 10 Best New Features in Visio 2010
    Scott Helmers gives live demonstrations of the top 10 new features in Visio 2010. This webinar will teach you how to create compelling diagrams by adding shapes to the page with a single click, linking the shapes in a diagram to data in Excel (or SQL Server, or SharePoint), ...
  3. IT Consultant Business Secrets Revealed
    Michael Munger, Experts Exchange tech pro and IT consultant, pulls back the curtain on his very successful businesses and answers question on every IT consultant and business owner should know about. He shares secrets on what he did to solve the 5 most common problems in IT, ...
  4. Disaster Recovery and Business Continuity
    Quest CTO, Mike Billon, gives an overview of the steps involved in building a dunamic disaster recovery plan. Through case studies and an examination of software/hardware tooles for monitoring and testing, you'll gain a better understandin of where you are, where you want ...
  5. Organize Your Visio Diagrams with Containers and Lists
    Scott Helmers uses cross functional flowcharts, wireframe diagrams, data graphic legends and seating charts to teach you: how to ustilize all three new structured diagram components in Visio 2010, the best practices for organizeing shapes in previous version of Visio, how to organize ...
  6. How to Us Objects, Properties, Events and Methods in Microsoft Access
    Alison Dalter gives an in-depbth look at objects, properties, events and methods in Microsoft Access. In this webinar you will learn about using the object browser, referring to objects, working with properties and methods, working with object variables, understanding the ...

Join the Community

Give a Little. Get a Lot.

Join the community of experts here and help other tech pros by answering question in your area of expertise. You can earn FREE access to all Experts Exchange's premium features and resources.

Join the Community

Answers

 

by: thenelsonPosted on 2009-11-04 at 11:20:26ID: 25742842

Use the add and remove functions:

Dim colCheckBox As New Collection

colCheckBox.Add CLng(rst!ID), CStr(rst!ID)

colCheckBox.Remove (CStr(Me.ID))

Then to Access the item:

colCheckBox(CStr(vID))

 

by: thenelsonPosted on 2009-11-04 at 11:25:51ID: 25742897

from VBA help:
Add Method
Adds a member to a Collection object.

Syntax

object.Add item, key, before, after

The Add method syntax has the following object qualifier and named arguments:

Part Description
object Required. An object expression that evaluates to an object in the Applies To list.

item Required. An expression of any type that specifies the member to add to the collection.

key Optional. A unique string expression that specifies a key string that can be used, instead of a positional index, to access a member of the collection.

before Optional. An expression that specifies a relative position in the collection. The member to be added is placed in the collection before the member identified by the before argument. If a numeric expression, before must be a number from 1 to the value of the collection's Count property. If a string expression, before must correspond to the key specified when the member being referred to was added to the collection. You can specify a before position or an after position, but not both.

after Optional. An expression that specifies a relative position in the collection. The member to be added is placed in the collection after the member identified by the after argument. If numeric, after must be a number from 1 to the value of the collection's Count property. If a string, after must correspond to the key specified when the member referred to was added to the collection. You can specify a before position or an after position, but not both.


Remove Method


Removes a member from a Collection object.

Syntax

object.Remove index

The Remove method syntax has the following object qualifier and part:

Part Description
object Required. An object expression that evaluates to an object in the Applies To list.

index Required. An expression that specifies the position of a member of the collection. If a numeric expression, index must be a number from 1 to the value of the collection's Count property. If a string expression, index must correspond to the key argument specified when the member referred to was added to the collection.


Item Method

Returns a specific member of a Collection object either by position or by key.

Syntax

object.Item(index)

The Item method syntax has the following object qualifier and part:

Part Description
object Required. An object expression that evaluates to an object in the Applies To list.

index Required. An expression that specifies the position of a member of the collection. If a numeric expression, index must be a number from 1 to the value of the collection's Count property. If a string expression, index must correspond to the key argument specified when the member referred to was added to the collection.


 

by: thenelsonPosted on 2009-11-04 at 11:28:43ID: 25742925

Oops Misread your question

try:
 Item = main("key")

 

by: thenelsonPosted on 2009-11-04 at 11:32:42ID: 25742966

If that doesn't work, you could try:

On Error Resume Next

    Set Item = main.Item("key")
If err = TheErrorNumber Then
    Item = main.Item("key")
Else
    'handle other errors
End If

 

by: GrahamMandenoPosted on 2009-11-04 at 11:43:17ID: 25743083

Try using IsObject()

If IsObject(main.Item("key")) Then
   Set Item = main.Item("key")
Else
   Item = main.Item("key")
End If

--
Graham

 

by: thenelsonPosted on 2009-11-04 at 11:59:33ID: 25743269

Nice Graham!

 

by: alainbrydenPosted on 2009-11-04 at 12:49:18ID: 25743749

Graham,

That would be the ideal solution except that when the collection is very large, searching by key takes a long time, and it isn't an operation I want to perform twice unless absolutely necessary.

In your example, irregardless of they type of the variant, the Item get property is called twice, which results in a large slowdown.

It seems thenelson provided, more or less, the solution I have been temporarily employing while waiting for something better:

'Retrieves an object with the x, y, z coordinate key specified
Public Function Item(ByVal x As Long, ByVal y As Long, ByVal z As Long) As Variant
    On Error Resume Next
    Set Item = main.Item(str(x)).Item(str(y)).Item(str(z))
    'If this error occured (type mismatch) then the element is a non-object type
    If Err.Number = 13 Then Item = main.Item(str(x)).Item(str(y)).Item(str(z))
    If Err.Number = 5 Then On Error GoTo 0: Err.Raise (5) 'The item does not exist
End Function

If you feel there are no alternatives that allow for a quick and generic retrieval, I'll have to keep it.

--
Alain

 

by: GrahamMandenoPosted on 2009-11-04 at 13:57:46ID: 25744424

Thanks, Nelson :-)

Hi Alain,

You've got me thinking now, so I hold you responsible for me getting no work done in the last hour ;-)

This is clearly a custom class module.  I thought of storing the IsObject result as a field in a UDT, but you can't add a UDT to a collection (not leastways in a class module).

So I thought about storing the items in an array and storing the array indices in the collection.  This seems to work quite well (see the snippet below).  Quite a useful concept, really - I called my Class module "Colflexion" :-)

--
Graham

Option Explicit
 
Private Type cfItem
  Item      As Variant
  Key       As String
  IsObject  As Boolean
End Type
 
Private Const cInitialSize      As Long = 2000
Private Const cExpandIncrement  As Long = 1000
 
Private aItems() As cfItem
Private colIndex As New Collection
Private lNextIndex As Long
 
Private Sub Class_Initialize()
ReDim aItems(cInitialSize)
End Sub
 
Public Sub Add(ByRef Item As Variant, Key As String)
If lNextIndex > UBound(aItems) Then
  ReDim Preserve aItems(UBound(aItems) + cExpandIncrement)
End If
With aItems(lNextIndex)
  .Key = Key
  .IsObject = IsObject(Item)
  If .IsObject Then
    Set .Item = Item
  Else
    Let .Item = Item
  End If
End With
colIndex.Add lNextIndex, Key
lNextIndex = lNextIndex + 1
End Sub
 
Public Function Item(Index As Variant, Optional ByRef Key As String) As Variant
Dim ix As Long
ix = colIndex.Item(Index)
With aItems(ix)
  Key = .Key
  If .IsObject Then
    Set Item = .Item
  Else
    Let Item = .Item
  End If
End With
End Function
                                              
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:

Select allOpen in new window

 

by: DatabaseMXPosted on 2009-11-04 at 13:59:44ID: 25744445

"so I hold you responsible for me getting no work done in the last hour ;-)"
OOPS!  LOL ... ok, what ELSE is new!

mx

 

by: thenelsonPosted on 2009-11-04 at 14:05:05ID: 25744485

Assuming Item is declared a variant, does this work?
Set Item = CVar(main.Item(str(x)).Item(str(y)).Item(str(z)))

or this?
Item = CVar(main.Item(str(x)).Item(str(y)).Item(str(z)))

I would at least use Else If to eliminate having to do both tests every time:
    If Err.Number = 13 Then
         Item = main.Item(str(x)).Item(str(y)).Item(str(z))
    ElseIf Err.Number = 5 Then
         On Error GoTo 0: Err.Raise (5) 'The item does not exist
    End If

 

by: thenelsonPosted on 2009-11-04 at 14:54:01ID: 25744963

Graham,
Very clever!  But why are you storing the key in the array? You don't really need it. You don't really use it.

Shouldn't this be called "Colray"? Where does the "...flexion" come from? ;-)

Nelson

 

by: GrahamMandenoPosted on 2009-11-04 at 15:04:27ID: 25745052

Hi Nelson

One of the things that has always annoyed me about collections is that you can't retrieve the key for an item - for example, you can't say:
   strTemp = col(25).Key
This would be very useful for, say, building a TreeView from a collection.

I thought I could solve that problem by storing the key in the item.

"Colflexion" was supposed to imply "flexible collection  ;-)

When I get time (not today!) I'll put some polish on it.  It needs to return a Count property, and also implement a Delete method and enhance the Add to include the other optional arguments.  Of course, the Delete method should do some garbage collection also.

--
Graham

 

by: DatabaseMXPosted on 2009-11-04 at 15:06:28ID: 25745074

"One of the things that has always annoyed me about collections is that you can't retrieve the key for an item "

Yes ... VERY annoying and weird !

mx

 

by: roryaPosted on 2009-11-04 at 16:16:11ID: 25745615

That's what Dictionaries are for... :)

 

by: alainbrydenPosted on 2009-11-05 at 13:01:08ID: 25753978

That's a good thought, Graham - wrapping each inserted variant in an node and storing the additional information about the variant type and key in that node. In the data structure I needed, I did something similar, but I hadn't thought of pre-computing the isObject value for later use in retrieval.

"you can't add a UDT to a collection" - not sure if your parenthesized annotation to this comment means what I'm about to say or not, but I did exactly that, just by defining my custom 'Type' as a Class. The downsides to this approach are that it becomes a public class and you have to have a separate class module for it, so I see why you did it the way you did with indexes. Your method also makes it much easier to iterate over all items in the list.


Anyways, I ended up using the 'error handling' method and moving on with my life, but the most agreeable method would certainly have been to store the isObject property on insertion (since I'm working with a custom data structure anyways) and then call upon it at item retrieval time for a quick check of the correct assignment method to use. As such, I'll give you point value for that solution.

--
Alain

 

by: thenelsonPosted on 2009-11-05 at 14:30:12ID: 25754812

Alain,

Did you try the CVar method I suggested in http:#a225744485?

Glad to help and thank you very much for the points with "A" grade!

Happy computing!

Nelson

 

by: GrahamMandenoPosted on 2009-11-05 at 16:15:33ID: 25755579

Hi Nelson

I think the problem is that after using CVar you can't get to any of the properties or methods of the object, which renders it pretty useless :-)

--
Graham

 

by: alainbrydenPosted on 2009-11-06 at 12:55:30ID: 25762959

Oh no, the CVar thing actually does nothing. Even if you are casting to Variant with CVar, when it goes to assign the new variable to the next one, it must dynamically type the object (which ignores the casting) to determine whether it will copy by value or by reference (duplicate the variable or create a new reference to the variable). As such, Cvar gives the same errors:

[code]
    Dim avar As Variant
   
   
    Dim str As String
    str = "hello world"
   
    Set avar = CVar(str) 'Err=13 (Type Mismatch Error)
    avar = CVar(str)
   
   
    Dim aobj As Object
    Set aobj = New Collection
   
    Set avar = CVar(aobj)
    avar = CVar(aobj) 'Err = 450 (Wrong number of arguments or invalid property assignment error)
[/code]

--
Alain

 

by: alainbrydenPosted on 2009-11-06 at 12:56:06ID: 25762963

@[code] tags - I've been spending too much time in Articles

--
Alain

20120131-EE-VQP-002

3 Ways to Join

30-Day Free Trial

The Experts

98% positive feedback on 31,087 answers since March 2000. angeliii is a Microsoft Most Valuable Professional for his work with MS SQL Server & Develoment.

He has also proven his knowledge of Visual Basic Programming, PHP Scripting and Oracle Databases.

The Experts

97% positive feedback on 10,752 answers since July 2000. lrmoore has more than 18 years experience in the networking industry.

The six-time Mircosoft MVPs specialties include firewalls, virtual private networking, and network management.

Testimonials

"...and excellent source for support... Kind of like having your very own IT dept." Electriciansnet

Testimonials

"I was apprehensive at signing up at first. However... it has already made my life as an IT administrator much easier." JaCrews

Testimonials

"WOW! You guys have great, active, and knowledgeable people on here." moore50

Business Clients

Business Clients

In the Press

"If you’ve got a question... Experts Exchange can supply an answer.”

In the Press

"...an invaluable aid for both IT professionals and those who require tech support."

In the Press

"where IT professionals provide quick answers on just about any topic"

Business Account Plans

Loading Advertisement...