Getting error when calling custom property - vba

I am looking to do a depth first searching algo using vba so i have defined an object called "node" which should contains a "parentNode".
I have tried to define parentNode as collection and use the following
Public Property Let Parent(ByRef inputNode As Node)
Set parentNode = New Collection
hasParentNode = True
parentNode.Add inputNode
End Property
Public Property Get Parent() As Node
Parent = parentNode.Item(1)
End Property
But when i call node.Parent i got Object variable or With block variable not set
i know that is due to the line "Parent = parentNode.Item(1)" what should be the proper way of doing this? I want it to return the parnetNode assigned by Ref
Thanks

Since Node is an object (I assume, I have no idea what class Node actually is), your code is missing the Set keyword:
Public Property Get Parent() As Node
Set Parent = parentNode.Item(1)
End Property
Getting Object variable or With block variable not set usually sometimes means a missing Set keyword.

Related

Out of Stack Space Error when setting Custom Object Parameter

I have a custom class module called Service with string parameters.
I instantiate the class by creating an object this_service like so:
Dim this_service As Service
Set this_service = New Service
Then I try to set a parameter to any string value like so:
this_service.Key = "HELLO"
When I run the macro I get the 28 Runtime Error, Out of Stack Space.
In my class module Service I have the following parameter definition and method calls:
Private pKey As String
Public Property Get Key() As String
Key = pKey
End Property
Public Property Let Key(Value As String)
Key = Value
End Property
I can't see any reason why I'd be getting this runtime error?
In Public Property Let it should be:
pKey = Value
Right now it calls the setter recursively (indefinitely).

Using CallByName to set Item(x) property

As a bit of background, I have a .net <-> COM object bridge that uses VB.net as a middleman, with a lot of reflection to get the job done.
I've run into a hurdle where I'm needing to use CallByName() to set a pretty standard property which is defined as
Public Default Property Item (
index As Integer
) As String
Get
Set
which would normally be called as .Object(1) = "new value", however the bridge code at the moment tries to get .Object(1) as an object then call Set on it using CallByName() (which obviously doesn't work).
With other collections I am happily able to use CallByName() to make method calls .Clear() and .Add("new value") but this property doesn't have these methods and besides, I'd like to solve it for a more generic approach so that code from the other side of the bridge can call the .Object directly.
Is someone able to suggest a way to Set an array-type property directly using CallByName(), or perhaps suggest an alternative reflection function that can be called to achieve this?
The default property can be used as a normal property, using its name. So, given a class:
Class Foo
Default Public Property Item(index As Integer) As String
Get
'...
End Get
Set(value As String)
'...
End Set
End Property
End Class
These three property assignments all have the same effect:
Dim Bar As New Foo
Bar(1) = "x"
Bar.Item(1) = "x"
CallByName(Bar, "Item", CallType.Set, 1, "x")
For array-type properties, the parameter(s) are passed to CallByName before the value when setting.
You did not show how you were using CallByName on that property, which leaves us to guess what is wrong. The syntax of .Object(1) = "new value" is also a little confusing: does the leading dot means that Object itself is some sort of collection on some other Type?
The basic answer lies in looking at the declaration, not how it is used normally. The fact that you can omit "Item" normally because it is the Default, does not apply here:
'foo(1) ==> foo.Item(1) = "Ziggy" ==>
CallByName(foo, "Item", CallType.Set, 1, "Ziggy")
The procName argument would be the property name, Item in this case. CallType.Set means you want the prop setter (Let or Set seem to both work). The first argument would be the index of the item to set/get, the last would be the data to pass.
If .Object is supposed to mean you are trying to reference a collection property, then the answer is about the same:
'foo.bars(1) ==> foo.Bars.Item(1) = "Zoey" ==>
CallByName(foo.Bars, "Item", CallType.Set, 1, "Zoey")

Call set of parent property when setting child properties

So in my class 'myInfo' I have an aliased property 'HeaderInfo' that is a property as a class, where it is actually the Header of a much deeper class.
Private _header As myHeader
Public Property HeaderInfo() AS myHeader
Get
Return _header
End Get
Set(ByVal value As myHeader)
_header = value
Someotherclass.Foo.Bar.AnotherThing.Header = _header
End Set
End Property
myHeader is a class with properties like 'Name', 'ID', etc. that are all strings. So when I reference this property in something like a Windows Form, I do
Dim info As New myInfo()
info.HeaderInfo.ID = "ID HERE"
info.HeaderInfo.Name = "Name here"
It works to the extent that the instance of the info.HeaderInfo is setting all its properties correctly, but
Someotherclass.Foo.Bar.AnotherThing.Header = _header
never gets set inside the myInfo.HeaderInfo 'Set', because I'm not directly setting the property, I'm setting its subproperties in assumption that it would propagate. Am I not understanding how properties with a custom type work? Is there a way to propagate this?
To make this happen automatically, you would need to alter the setter for the properties in your myHeader type, and for that to work your type instances have to know about the specific instance of your myInfo type.
Let's look at why this doesn't work they way you hoped. To do that, I'll break apart this statement:
info.HeaderInfo.ID = "ID HERE"
When that statement is executed, first the info variable must be de-referenced to get the object instance it refers to.1 When we have that object, we have to get (not set) the HeaderInfo property, so that we have a reference to the your myHeader object instance. Once we have the myHeader object, we call the setter on the ID property to complete the assignment.
Hopefully that clears up why this works the way it does. You do access the HeaderInfo property, but you only ever use the getter.
1Side note: if you ever see the "Object reference not set to instance of object" this is what it's talking about: a variable or property that you did not expect in an expression was Nothing/null.

Returning an object of a second class through the constructor of first class

I have a node class and a tree class. I have defined the node class to contain the properties needed for a node declaration and the tree class is used to form a tree structure from the nodes. While the tree structure is formed from the node, I am having a problem in returning the node object. My code structure is:
classdef Node
properties
node_center;
node_size;
end
methods
function this = Node(center,size)
this.node_center = center;
this.node_size = size;
end
end
end % end of class Node
classdef Tree < handle
methods
function n = Tree(points,objects_in_tree)
n = Node(center_of_points,size);
n = insert_child(n,center,sizez);
end
end
Now the error I am getting is:
When constructing an instance of class 'Tree', the constructor must preserve the class of the returned object.
I know the reason of why its happening but would like to know the workaround to this. Thanks.
The return value from the constructor must be the object created - there's no way around it. You can make another function that returns the other values (like the Node) that you would like to get out of it. After the Tree is constructed, call the accessor function on that object.

In VB6 what is the difference between Property Set and Property Let?

I have just created several Property Set methods, and they didn't compile. When I changed them to Property Let, everything was fine.
I have since studied the documentation to find the difference between Property Set and Property Let, but must admit to being none the wiser. Is there any difference, and if so could someone offer a pointer to a proper explanation of it?
Property Set is for objects (e.g., class instances)
Property Let is for "normal" datatypes (e.g., string, boolean, long, etc.)
Property Let is more versatile than Property Set. The latter is restricted to object references only. If you have this property in a class
Private m_oPicture As StdPicture
Property Get Picture() As StdPicture
Set Picture = m_oPicture
End Property
Property Set Picture(oValue As StdPicture)
Set m_oPicture = oValue
End Property
Property Let Picture(oValue As StdPicture)
Set m_oPicture = oValue
End Property
You can call Property Set Picture with
Set oObj.Picture = Me.Picture
You can call Property Let Picture with both
Let oObj.Picture = Me.Picture
oObj.Picture = Me.Picture
Implementing Property Set is what other developers expect for properties that are object references but sometimes even Microsoft provide only Property Let for reference properties, leading to the unusual syntax oObj.Object = MyObject without Set statement. In this case using Set statement leads to compile-time or run-time error because there is no Property Set Object implemented on oObj class.
I tend to implement both Property Set and Property Let for properties of standard types -- fonts, pictures, etc -- but with different semantics. Usually on Property Let I tend to perform "deep copy", i.e. cloning the StdFont instead of just holding a reference to the original object.
Property Set is for object-like variables (ByRef) whereas Property Let is for value-like variables (ByVal)