Why does an object returning itself as the default property hang excel and crash the debugger?












2















I recently came accross `Attribute Values.VB_UserMemId = 0'. I like lists so I thought I'd build a bespoke collection type object.



The minimal code for the class that can reproduce the error is:



Class Lst



Option Explicit

Public c As New Collection

'this is the default property
Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0
If IsMissing(index) Then
Set item = Me
'DoEvents
Else
item = c(index)
End If
End Property

Public Property Let item(Optional index, itm)
If IsMissing(index) Then 'assume itm is list
If IsObject(itm) Then Set c = itm.c Else c.add itm
Else
c.add itm, , index
c.Remove index + 1
End If
End Property


Essentially, lst(i) returns the ith element of the private collection, Lst(i)=6 sets the ith element. (errorhandling and index checking code stripped for clarity).



I noticed that objects that return themselves from the default property can be returned from a function in a variant (e.g LstFunc=L below), without the need for a set removing complexity from my students eyes...(you cant do that with a collection object)



Unfortunately, I encountered two challenges...the minimum code for these is:



The Problem



Function LstFunc() As Variant
Dim L As New Lst
L = 4 'replaces L.item=3
LstFunc = L 'this is not normally allowed, but desirable (for me!)
End Function

Sub try()
Dim L As New Lst
L = LstFunc 'replaces L.item=LstFunc-->L.c: [4]
L = 3 'L.c: [4,3]
If L = 6 Then DoEvents
End Sub


Here is what happens



1) when the expression L = 6 is evaluated excel hangs. Some times ESC gets you it back in, but my experience is that excel stops responding and needs a restart.



To evaluate the expression the L.item function is called initially, returning a Lst, for which item is called, etc.etc. resulting in unwanted, and undetected infinite repetition (not quite recursion). Uncommenting the DoEvents statement in the get item property allows you to stop without a crash



2) after uncommenting the DoEvents, I run in debugger mode step by step. If i now hover (by accident..) over the variable L, the debugger crashes, and I get the green triangle of death, which I fear will be very confusing for the students:
green triangle of death...



Note this behaviour is recoverable if the DoEvents statement in the class is commented out again. A veritable catch 22...



Bit of an intricate one this, but any sugesstions as to how I can trap the unwanted repetition in (1) at low computational cost and without losing the ability to pass the object like a variant would be greatfully received.



PS this is a code snipped that provides an unsafe workaround discussed in a comment below:



Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0
static i
If IsMissing(index) Then
Set item = Me
i=i+1:if i>1000 then item="":exit property
'DoEvents
Else
item = c(index)
i=0
End If
End Property









share|improve this question




















  • 1





    I'm not sure what you mean by "trap the unwanted recursion". Also, I'm not clear on what the purpose of having an object return itself from the default method is. You always have the ability to "pass the object like a variant" in that anything can be stored in a Variant.

    – Comintern
    Nov 26 '18 at 2:33











  • Probably should have used 'unintended' infinite repetition caused by evaluation of the p=6 statement as technically it calls L.item repeatedly rather than recursively

    – vbAdder
    Nov 26 '18 at 8:35













  • Re the 'returning itself' this is quite distinctly different, note in the code above I work with objects and can treat them as variants, SET is not used at all. you can't return a collection from a function without using Set; one thing less for the students unfamiliar with VBA to get wrong.

    – vbAdder
    Nov 26 '18 at 8:46
















2















I recently came accross `Attribute Values.VB_UserMemId = 0'. I like lists so I thought I'd build a bespoke collection type object.



The minimal code for the class that can reproduce the error is:



Class Lst



Option Explicit

Public c As New Collection

'this is the default property
Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0
If IsMissing(index) Then
Set item = Me
'DoEvents
Else
item = c(index)
End If
End Property

Public Property Let item(Optional index, itm)
If IsMissing(index) Then 'assume itm is list
If IsObject(itm) Then Set c = itm.c Else c.add itm
Else
c.add itm, , index
c.Remove index + 1
End If
End Property


Essentially, lst(i) returns the ith element of the private collection, Lst(i)=6 sets the ith element. (errorhandling and index checking code stripped for clarity).



I noticed that objects that return themselves from the default property can be returned from a function in a variant (e.g LstFunc=L below), without the need for a set removing complexity from my students eyes...(you cant do that with a collection object)



Unfortunately, I encountered two challenges...the minimum code for these is:



The Problem



Function LstFunc() As Variant
Dim L As New Lst
L = 4 'replaces L.item=3
LstFunc = L 'this is not normally allowed, but desirable (for me!)
End Function

Sub try()
Dim L As New Lst
L = LstFunc 'replaces L.item=LstFunc-->L.c: [4]
L = 3 'L.c: [4,3]
If L = 6 Then DoEvents
End Sub


Here is what happens



1) when the expression L = 6 is evaluated excel hangs. Some times ESC gets you it back in, but my experience is that excel stops responding and needs a restart.



To evaluate the expression the L.item function is called initially, returning a Lst, for which item is called, etc.etc. resulting in unwanted, and undetected infinite repetition (not quite recursion). Uncommenting the DoEvents statement in the get item property allows you to stop without a crash



2) after uncommenting the DoEvents, I run in debugger mode step by step. If i now hover (by accident..) over the variable L, the debugger crashes, and I get the green triangle of death, which I fear will be very confusing for the students:
green triangle of death...



Note this behaviour is recoverable if the DoEvents statement in the class is commented out again. A veritable catch 22...



Bit of an intricate one this, but any sugesstions as to how I can trap the unwanted repetition in (1) at low computational cost and without losing the ability to pass the object like a variant would be greatfully received.



PS this is a code snipped that provides an unsafe workaround discussed in a comment below:



Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0
static i
If IsMissing(index) Then
Set item = Me
i=i+1:if i>1000 then item="":exit property
'DoEvents
Else
item = c(index)
i=0
End If
End Property









share|improve this question




















  • 1





    I'm not sure what you mean by "trap the unwanted recursion". Also, I'm not clear on what the purpose of having an object return itself from the default method is. You always have the ability to "pass the object like a variant" in that anything can be stored in a Variant.

    – Comintern
    Nov 26 '18 at 2:33











  • Probably should have used 'unintended' infinite repetition caused by evaluation of the p=6 statement as technically it calls L.item repeatedly rather than recursively

    – vbAdder
    Nov 26 '18 at 8:35













  • Re the 'returning itself' this is quite distinctly different, note in the code above I work with objects and can treat them as variants, SET is not used at all. you can't return a collection from a function without using Set; one thing less for the students unfamiliar with VBA to get wrong.

    – vbAdder
    Nov 26 '18 at 8:46














2












2








2


1






I recently came accross `Attribute Values.VB_UserMemId = 0'. I like lists so I thought I'd build a bespoke collection type object.



The minimal code for the class that can reproduce the error is:



Class Lst



Option Explicit

Public c As New Collection

'this is the default property
Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0
If IsMissing(index) Then
Set item = Me
'DoEvents
Else
item = c(index)
End If
End Property

Public Property Let item(Optional index, itm)
If IsMissing(index) Then 'assume itm is list
If IsObject(itm) Then Set c = itm.c Else c.add itm
Else
c.add itm, , index
c.Remove index + 1
End If
End Property


Essentially, lst(i) returns the ith element of the private collection, Lst(i)=6 sets the ith element. (errorhandling and index checking code stripped for clarity).



I noticed that objects that return themselves from the default property can be returned from a function in a variant (e.g LstFunc=L below), without the need for a set removing complexity from my students eyes...(you cant do that with a collection object)



Unfortunately, I encountered two challenges...the minimum code for these is:



The Problem



Function LstFunc() As Variant
Dim L As New Lst
L = 4 'replaces L.item=3
LstFunc = L 'this is not normally allowed, but desirable (for me!)
End Function

Sub try()
Dim L As New Lst
L = LstFunc 'replaces L.item=LstFunc-->L.c: [4]
L = 3 'L.c: [4,3]
If L = 6 Then DoEvents
End Sub


Here is what happens



1) when the expression L = 6 is evaluated excel hangs. Some times ESC gets you it back in, but my experience is that excel stops responding and needs a restart.



To evaluate the expression the L.item function is called initially, returning a Lst, for which item is called, etc.etc. resulting in unwanted, and undetected infinite repetition (not quite recursion). Uncommenting the DoEvents statement in the get item property allows you to stop without a crash



2) after uncommenting the DoEvents, I run in debugger mode step by step. If i now hover (by accident..) over the variable L, the debugger crashes, and I get the green triangle of death, which I fear will be very confusing for the students:
green triangle of death...



Note this behaviour is recoverable if the DoEvents statement in the class is commented out again. A veritable catch 22...



Bit of an intricate one this, but any sugesstions as to how I can trap the unwanted repetition in (1) at low computational cost and without losing the ability to pass the object like a variant would be greatfully received.



PS this is a code snipped that provides an unsafe workaround discussed in a comment below:



Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0
static i
If IsMissing(index) Then
Set item = Me
i=i+1:if i>1000 then item="":exit property
'DoEvents
Else
item = c(index)
i=0
End If
End Property









share|improve this question
















I recently came accross `Attribute Values.VB_UserMemId = 0'. I like lists so I thought I'd build a bespoke collection type object.



The minimal code for the class that can reproduce the error is:



Class Lst



Option Explicit

Public c As New Collection

'this is the default property
Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0
If IsMissing(index) Then
Set item = Me
'DoEvents
Else
item = c(index)
End If
End Property

Public Property Let item(Optional index, itm)
If IsMissing(index) Then 'assume itm is list
If IsObject(itm) Then Set c = itm.c Else c.add itm
Else
c.add itm, , index
c.Remove index + 1
End If
End Property


Essentially, lst(i) returns the ith element of the private collection, Lst(i)=6 sets the ith element. (errorhandling and index checking code stripped for clarity).



I noticed that objects that return themselves from the default property can be returned from a function in a variant (e.g LstFunc=L below), without the need for a set removing complexity from my students eyes...(you cant do that with a collection object)



Unfortunately, I encountered two challenges...the minimum code for these is:



The Problem



Function LstFunc() As Variant
Dim L As New Lst
L = 4 'replaces L.item=3
LstFunc = L 'this is not normally allowed, but desirable (for me!)
End Function

Sub try()
Dim L As New Lst
L = LstFunc 'replaces L.item=LstFunc-->L.c: [4]
L = 3 'L.c: [4,3]
If L = 6 Then DoEvents
End Sub


Here is what happens



1) when the expression L = 6 is evaluated excel hangs. Some times ESC gets you it back in, but my experience is that excel stops responding and needs a restart.



To evaluate the expression the L.item function is called initially, returning a Lst, for which item is called, etc.etc. resulting in unwanted, and undetected infinite repetition (not quite recursion). Uncommenting the DoEvents statement in the get item property allows you to stop without a crash



2) after uncommenting the DoEvents, I run in debugger mode step by step. If i now hover (by accident..) over the variable L, the debugger crashes, and I get the green triangle of death, which I fear will be very confusing for the students:
green triangle of death...



Note this behaviour is recoverable if the DoEvents statement in the class is commented out again. A veritable catch 22...



Bit of an intricate one this, but any sugesstions as to how I can trap the unwanted repetition in (1) at low computational cost and without losing the ability to pass the object like a variant would be greatfully received.



PS this is a code snipped that provides an unsafe workaround discussed in a comment below:



Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0
static i
If IsMissing(index) Then
Set item = Me
i=i+1:if i>1000 then item="":exit property
'DoEvents
Else
item = c(index)
i=0
End If
End Property






excel vba class default






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 26 '18 at 17:59







vbAdder

















asked Nov 26 '18 at 2:19









vbAddervbAdder

1446




1446








  • 1





    I'm not sure what you mean by "trap the unwanted recursion". Also, I'm not clear on what the purpose of having an object return itself from the default method is. You always have the ability to "pass the object like a variant" in that anything can be stored in a Variant.

    – Comintern
    Nov 26 '18 at 2:33











  • Probably should have used 'unintended' infinite repetition caused by evaluation of the p=6 statement as technically it calls L.item repeatedly rather than recursively

    – vbAdder
    Nov 26 '18 at 8:35













  • Re the 'returning itself' this is quite distinctly different, note in the code above I work with objects and can treat them as variants, SET is not used at all. you can't return a collection from a function without using Set; one thing less for the students unfamiliar with VBA to get wrong.

    – vbAdder
    Nov 26 '18 at 8:46














  • 1





    I'm not sure what you mean by "trap the unwanted recursion". Also, I'm not clear on what the purpose of having an object return itself from the default method is. You always have the ability to "pass the object like a variant" in that anything can be stored in a Variant.

    – Comintern
    Nov 26 '18 at 2:33











  • Probably should have used 'unintended' infinite repetition caused by evaluation of the p=6 statement as technically it calls L.item repeatedly rather than recursively

    – vbAdder
    Nov 26 '18 at 8:35













  • Re the 'returning itself' this is quite distinctly different, note in the code above I work with objects and can treat them as variants, SET is not used at all. you can't return a collection from a function without using Set; one thing less for the students unfamiliar with VBA to get wrong.

    – vbAdder
    Nov 26 '18 at 8:46








1




1





I'm not sure what you mean by "trap the unwanted recursion". Also, I'm not clear on what the purpose of having an object return itself from the default method is. You always have the ability to "pass the object like a variant" in that anything can be stored in a Variant.

– Comintern
Nov 26 '18 at 2:33





I'm not sure what you mean by "trap the unwanted recursion". Also, I'm not clear on what the purpose of having an object return itself from the default method is. You always have the ability to "pass the object like a variant" in that anything can be stored in a Variant.

– Comintern
Nov 26 '18 at 2:33













Probably should have used 'unintended' infinite repetition caused by evaluation of the p=6 statement as technically it calls L.item repeatedly rather than recursively

– vbAdder
Nov 26 '18 at 8:35







Probably should have used 'unintended' infinite repetition caused by evaluation of the p=6 statement as technically it calls L.item repeatedly rather than recursively

– vbAdder
Nov 26 '18 at 8:35















Re the 'returning itself' this is quite distinctly different, note in the code above I work with objects and can treat them as variants, SET is not used at all. you can't return a collection from a function without using Set; one thing less for the students unfamiliar with VBA to get wrong.

– vbAdder
Nov 26 '18 at 8:46





Re the 'returning itself' this is quite distinctly different, note in the code above I work with objects and can treat them as variants, SET is not used at all. you can't return a collection from a function without using Set; one thing less for the students unfamiliar with VBA to get wrong.

– vbAdder
Nov 26 '18 at 8:46












1 Answer
1






active

oldest

votes


















2














The recursion can't be avoided.



From section 5.6.2.2 of the VBA language specification:





  • If the expression’s value type is a specific class:


    • If the source object has a public default Property Get or a public default function, and this default member’s parameter list is
      compatible with an argument list containing 0 parameters, the simple
      data value’s value is the result of evaluating this default member as
      a simple data value.






Note that with your sample class, this line of code meets all of those conditions:




If L = 6 Then DoEvents



The type of the expression L = 6 is Boolean, with an Lst on the left hand side and an Integer on the right hand side. That means the type of the comparison is Integer, so the run-time checks to see if there is a default Property Get, which you provide here:




Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0



The parameter list is compatible with an argument list containing 0 parameters, because the index is optional. So, it evaluates to L.item() = 6. The only test you do inside the property is If IsMissing(index), which is guaranteed to be true if it's called as the default member - remember, it can't require a parameter to be passed. As you found out, this leads you to...




5.6.2.3 Default Member Recursion Limits



Evaluation of an object whose default Property Get or default function
returns another object can lead to a recursive evaluation process if
the returned object has a further default member. Recursion through
this chain of default members may be implicit if evaluating to a
simple data value and each default member has an empty parameter list,
or explicit if index expressions are specified that specifically
parameterize each default member.




How this is handled is implementation specific. Office VBA implementations, however, do not cap the recursion depth and will simply crash the host when it runs out of stack space.





That said, the rest of your question is simply an x-y problem, although my suggestion is to scrap this. Using default members hides the intent of your code and robust, maintainable code should be readable.






share|improve this answer
























  • I haven't looked at OP's code in details, but I believe such a recursive default member implementation can also crash the locals debugger toolwindow.

    – Mathieu Guindon
    Nov 26 '18 at 3:37











  • @MathieuGuindon I'm guessing that it would - I haven't loaded up the OP's class in the VBE, but I'd be surprised if it didn't exhibit the same behavior as hovering over the variable in the debugger.

    – Comintern
    Nov 26 '18 at 3:39











  • @above two gents, much appreciated you response time! Note the behaviour is different, and depends on whether the doevent statement is uncommented or not.

    – vbAdder
    Nov 26 '18 at 8:41











  • I now do have a 'solution', I added a static counter to the get item property, and return a string if the counter goes over 1000; counter is set to zero if an index was provided to reset. So as long as L(1) is called once in every 999 L() calls, it will work. Note this will fail if we add 1001 items to the list.... something better would be nice!

    – vbAdder
    Nov 26 '18 at 8:51











  • @comintern I looked at what is mend by XY-problem :-) agree there is an element of that, though the response of the debugger to the introduction of the Doevent statement has not been clarified.

    – vbAdder
    Nov 26 '18 at 18:06













Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53473985%2fwhy-does-an-object-returning-itself-as-the-default-property-hang-excel-and-crash%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









2














The recursion can't be avoided.



From section 5.6.2.2 of the VBA language specification:





  • If the expression’s value type is a specific class:


    • If the source object has a public default Property Get or a public default function, and this default member’s parameter list is
      compatible with an argument list containing 0 parameters, the simple
      data value’s value is the result of evaluating this default member as
      a simple data value.






Note that with your sample class, this line of code meets all of those conditions:




If L = 6 Then DoEvents



The type of the expression L = 6 is Boolean, with an Lst on the left hand side and an Integer on the right hand side. That means the type of the comparison is Integer, so the run-time checks to see if there is a default Property Get, which you provide here:




Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0



The parameter list is compatible with an argument list containing 0 parameters, because the index is optional. So, it evaluates to L.item() = 6. The only test you do inside the property is If IsMissing(index), which is guaranteed to be true if it's called as the default member - remember, it can't require a parameter to be passed. As you found out, this leads you to...




5.6.2.3 Default Member Recursion Limits



Evaluation of an object whose default Property Get or default function
returns another object can lead to a recursive evaluation process if
the returned object has a further default member. Recursion through
this chain of default members may be implicit if evaluating to a
simple data value and each default member has an empty parameter list,
or explicit if index expressions are specified that specifically
parameterize each default member.




How this is handled is implementation specific. Office VBA implementations, however, do not cap the recursion depth and will simply crash the host when it runs out of stack space.





That said, the rest of your question is simply an x-y problem, although my suggestion is to scrap this. Using default members hides the intent of your code and robust, maintainable code should be readable.






share|improve this answer
























  • I haven't looked at OP's code in details, but I believe such a recursive default member implementation can also crash the locals debugger toolwindow.

    – Mathieu Guindon
    Nov 26 '18 at 3:37











  • @MathieuGuindon I'm guessing that it would - I haven't loaded up the OP's class in the VBE, but I'd be surprised if it didn't exhibit the same behavior as hovering over the variable in the debugger.

    – Comintern
    Nov 26 '18 at 3:39











  • @above two gents, much appreciated you response time! Note the behaviour is different, and depends on whether the doevent statement is uncommented or not.

    – vbAdder
    Nov 26 '18 at 8:41











  • I now do have a 'solution', I added a static counter to the get item property, and return a string if the counter goes over 1000; counter is set to zero if an index was provided to reset. So as long as L(1) is called once in every 999 L() calls, it will work. Note this will fail if we add 1001 items to the list.... something better would be nice!

    – vbAdder
    Nov 26 '18 at 8:51











  • @comintern I looked at what is mend by XY-problem :-) agree there is an element of that, though the response of the debugger to the introduction of the Doevent statement has not been clarified.

    – vbAdder
    Nov 26 '18 at 18:06


















2














The recursion can't be avoided.



From section 5.6.2.2 of the VBA language specification:





  • If the expression’s value type is a specific class:


    • If the source object has a public default Property Get or a public default function, and this default member’s parameter list is
      compatible with an argument list containing 0 parameters, the simple
      data value’s value is the result of evaluating this default member as
      a simple data value.






Note that with your sample class, this line of code meets all of those conditions:




If L = 6 Then DoEvents



The type of the expression L = 6 is Boolean, with an Lst on the left hand side and an Integer on the right hand side. That means the type of the comparison is Integer, so the run-time checks to see if there is a default Property Get, which you provide here:




Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0



The parameter list is compatible with an argument list containing 0 parameters, because the index is optional. So, it evaluates to L.item() = 6. The only test you do inside the property is If IsMissing(index), which is guaranteed to be true if it's called as the default member - remember, it can't require a parameter to be passed. As you found out, this leads you to...




5.6.2.3 Default Member Recursion Limits



Evaluation of an object whose default Property Get or default function
returns another object can lead to a recursive evaluation process if
the returned object has a further default member. Recursion through
this chain of default members may be implicit if evaluating to a
simple data value and each default member has an empty parameter list,
or explicit if index expressions are specified that specifically
parameterize each default member.




How this is handled is implementation specific. Office VBA implementations, however, do not cap the recursion depth and will simply crash the host when it runs out of stack space.





That said, the rest of your question is simply an x-y problem, although my suggestion is to scrap this. Using default members hides the intent of your code and robust, maintainable code should be readable.






share|improve this answer
























  • I haven't looked at OP's code in details, but I believe such a recursive default member implementation can also crash the locals debugger toolwindow.

    – Mathieu Guindon
    Nov 26 '18 at 3:37











  • @MathieuGuindon I'm guessing that it would - I haven't loaded up the OP's class in the VBE, but I'd be surprised if it didn't exhibit the same behavior as hovering over the variable in the debugger.

    – Comintern
    Nov 26 '18 at 3:39











  • @above two gents, much appreciated you response time! Note the behaviour is different, and depends on whether the doevent statement is uncommented or not.

    – vbAdder
    Nov 26 '18 at 8:41











  • I now do have a 'solution', I added a static counter to the get item property, and return a string if the counter goes over 1000; counter is set to zero if an index was provided to reset. So as long as L(1) is called once in every 999 L() calls, it will work. Note this will fail if we add 1001 items to the list.... something better would be nice!

    – vbAdder
    Nov 26 '18 at 8:51











  • @comintern I looked at what is mend by XY-problem :-) agree there is an element of that, though the response of the debugger to the introduction of the Doevent statement has not been clarified.

    – vbAdder
    Nov 26 '18 at 18:06
















2












2








2







The recursion can't be avoided.



From section 5.6.2.2 of the VBA language specification:





  • If the expression’s value type is a specific class:


    • If the source object has a public default Property Get or a public default function, and this default member’s parameter list is
      compatible with an argument list containing 0 parameters, the simple
      data value’s value is the result of evaluating this default member as
      a simple data value.






Note that with your sample class, this line of code meets all of those conditions:




If L = 6 Then DoEvents



The type of the expression L = 6 is Boolean, with an Lst on the left hand side and an Integer on the right hand side. That means the type of the comparison is Integer, so the run-time checks to see if there is a default Property Get, which you provide here:




Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0



The parameter list is compatible with an argument list containing 0 parameters, because the index is optional. So, it evaluates to L.item() = 6. The only test you do inside the property is If IsMissing(index), which is guaranteed to be true if it's called as the default member - remember, it can't require a parameter to be passed. As you found out, this leads you to...




5.6.2.3 Default Member Recursion Limits



Evaluation of an object whose default Property Get or default function
returns another object can lead to a recursive evaluation process if
the returned object has a further default member. Recursion through
this chain of default members may be implicit if evaluating to a
simple data value and each default member has an empty parameter list,
or explicit if index expressions are specified that specifically
parameterize each default member.




How this is handled is implementation specific. Office VBA implementations, however, do not cap the recursion depth and will simply crash the host when it runs out of stack space.





That said, the rest of your question is simply an x-y problem, although my suggestion is to scrap this. Using default members hides the intent of your code and robust, maintainable code should be readable.






share|improve this answer













The recursion can't be avoided.



From section 5.6.2.2 of the VBA language specification:





  • If the expression’s value type is a specific class:


    • If the source object has a public default Property Get or a public default function, and this default member’s parameter list is
      compatible with an argument list containing 0 parameters, the simple
      data value’s value is the result of evaluating this default member as
      a simple data value.






Note that with your sample class, this line of code meets all of those conditions:




If L = 6 Then DoEvents



The type of the expression L = 6 is Boolean, with an Lst on the left hand side and an Integer on the right hand side. That means the type of the comparison is Integer, so the run-time checks to see if there is a default Property Get, which you provide here:




Public Property Get item(Optional index)
'Attribute Values.VB_UserMemId = 0



The parameter list is compatible with an argument list containing 0 parameters, because the index is optional. So, it evaluates to L.item() = 6. The only test you do inside the property is If IsMissing(index), which is guaranteed to be true if it's called as the default member - remember, it can't require a parameter to be passed. As you found out, this leads you to...




5.6.2.3 Default Member Recursion Limits



Evaluation of an object whose default Property Get or default function
returns another object can lead to a recursive evaluation process if
the returned object has a further default member. Recursion through
this chain of default members may be implicit if evaluating to a
simple data value and each default member has an empty parameter list,
or explicit if index expressions are specified that specifically
parameterize each default member.




How this is handled is implementation specific. Office VBA implementations, however, do not cap the recursion depth and will simply crash the host when it runs out of stack space.





That said, the rest of your question is simply an x-y problem, although my suggestion is to scrap this. Using default members hides the intent of your code and robust, maintainable code should be readable.







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 26 '18 at 3:06









CominternComintern

18.7k42456




18.7k42456













  • I haven't looked at OP's code in details, but I believe such a recursive default member implementation can also crash the locals debugger toolwindow.

    – Mathieu Guindon
    Nov 26 '18 at 3:37











  • @MathieuGuindon I'm guessing that it would - I haven't loaded up the OP's class in the VBE, but I'd be surprised if it didn't exhibit the same behavior as hovering over the variable in the debugger.

    – Comintern
    Nov 26 '18 at 3:39











  • @above two gents, much appreciated you response time! Note the behaviour is different, and depends on whether the doevent statement is uncommented or not.

    – vbAdder
    Nov 26 '18 at 8:41











  • I now do have a 'solution', I added a static counter to the get item property, and return a string if the counter goes over 1000; counter is set to zero if an index was provided to reset. So as long as L(1) is called once in every 999 L() calls, it will work. Note this will fail if we add 1001 items to the list.... something better would be nice!

    – vbAdder
    Nov 26 '18 at 8:51











  • @comintern I looked at what is mend by XY-problem :-) agree there is an element of that, though the response of the debugger to the introduction of the Doevent statement has not been clarified.

    – vbAdder
    Nov 26 '18 at 18:06





















  • I haven't looked at OP's code in details, but I believe such a recursive default member implementation can also crash the locals debugger toolwindow.

    – Mathieu Guindon
    Nov 26 '18 at 3:37











  • @MathieuGuindon I'm guessing that it would - I haven't loaded up the OP's class in the VBE, but I'd be surprised if it didn't exhibit the same behavior as hovering over the variable in the debugger.

    – Comintern
    Nov 26 '18 at 3:39











  • @above two gents, much appreciated you response time! Note the behaviour is different, and depends on whether the doevent statement is uncommented or not.

    – vbAdder
    Nov 26 '18 at 8:41











  • I now do have a 'solution', I added a static counter to the get item property, and return a string if the counter goes over 1000; counter is set to zero if an index was provided to reset. So as long as L(1) is called once in every 999 L() calls, it will work. Note this will fail if we add 1001 items to the list.... something better would be nice!

    – vbAdder
    Nov 26 '18 at 8:51











  • @comintern I looked at what is mend by XY-problem :-) agree there is an element of that, though the response of the debugger to the introduction of the Doevent statement has not been clarified.

    – vbAdder
    Nov 26 '18 at 18:06



















I haven't looked at OP's code in details, but I believe such a recursive default member implementation can also crash the locals debugger toolwindow.

– Mathieu Guindon
Nov 26 '18 at 3:37





I haven't looked at OP's code in details, but I believe such a recursive default member implementation can also crash the locals debugger toolwindow.

– Mathieu Guindon
Nov 26 '18 at 3:37













@MathieuGuindon I'm guessing that it would - I haven't loaded up the OP's class in the VBE, but I'd be surprised if it didn't exhibit the same behavior as hovering over the variable in the debugger.

– Comintern
Nov 26 '18 at 3:39





@MathieuGuindon I'm guessing that it would - I haven't loaded up the OP's class in the VBE, but I'd be surprised if it didn't exhibit the same behavior as hovering over the variable in the debugger.

– Comintern
Nov 26 '18 at 3:39













@above two gents, much appreciated you response time! Note the behaviour is different, and depends on whether the doevent statement is uncommented or not.

– vbAdder
Nov 26 '18 at 8:41





@above two gents, much appreciated you response time! Note the behaviour is different, and depends on whether the doevent statement is uncommented or not.

– vbAdder
Nov 26 '18 at 8:41













I now do have a 'solution', I added a static counter to the get item property, and return a string if the counter goes over 1000; counter is set to zero if an index was provided to reset. So as long as L(1) is called once in every 999 L() calls, it will work. Note this will fail if we add 1001 items to the list.... something better would be nice!

– vbAdder
Nov 26 '18 at 8:51





I now do have a 'solution', I added a static counter to the get item property, and return a string if the counter goes over 1000; counter is set to zero if an index was provided to reset. So as long as L(1) is called once in every 999 L() calls, it will work. Note this will fail if we add 1001 items to the list.... something better would be nice!

– vbAdder
Nov 26 '18 at 8:51













@comintern I looked at what is mend by XY-problem :-) agree there is an element of that, though the response of the debugger to the introduction of the Doevent statement has not been clarified.

– vbAdder
Nov 26 '18 at 18:06







@comintern I looked at what is mend by XY-problem :-) agree there is an element of that, though the response of the debugger to the introduction of the Doevent statement has not been clarified.

– vbAdder
Nov 26 '18 at 18:06




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53473985%2fwhy-does-an-object-returning-itself-as-the-default-property-hang-excel-and-crash%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

Calculate evaluation metrics using cross_val_predict sklearn

Insert data from modal to MySQL (multiple modal on website)