×
INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Contact US

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Students Click Here

Hanging object reference from trifecta of Type(), _Access(), and .Parent [SOLVED]
3

Hanging object reference from trifecta of Type(), _Access(), and .Parent [SOLVED]

Hanging object reference from trifecta of Type(), _Access(), and .Parent [SOLVED]

2
(OP)
This took two days to track down, so I figured it deserved posting for posterity.

We came upon a situation where the simple solution to our problem was to add an _Access method to an object-type property which would go dynamically retrieve the requested object for us.
In another segment of code we needed to know whether or not the parent object was hanging off of a form class so we could display an error message rather than just log it.
This code used TYPE() as a guard because the expression tested for a Parent reference and, as you all know, VARTYPE() blows up in that scenario.

Don't do all three of these things together!

The offending line of code in the below sample is in Chatty:Test() and evaluates to this: TYPE("this.ioChild.Parent").
This TYPE() invocation causes a dangling object reference to the object returned from the ioChild_Access() method.

The only way, it appears, to get this issue to happen is when all three of: TYPE(), _Access(), and .Parent appear in the statement.

For example, setting a local variable to the object returned from the access method and then using TYPE() to test its Parent reference works fine.
Using an actual object reference which does not have an access method works fine. (See the "Ok" case below)

But, for the love of FoxPro, DO NOT DO ALL THREE TOGETHER.

Sample code:

CODE

CLEAR

Talk("DoDemo() - Begin")
DoDemo()
Talk("DoDemo() - End")

RETURN

PROCEDURE DoDemo
	Talk("Begin")
	
	LOCAL loObj AS Object
	loObj = CREATEOBJECT("Chatty")
	loObj.Test()
	
	Talk("End")
ENDPROC

PROCEDURE Talk
	LPARAMETERS tuObj
	
	LOCAL lcPrefix AS String, lcProc AS String
	lcPrefix = REPLICATE("  ", MAX(PROGRAM(-1) - 1, 0))
	lcProc = PROGRAM(PROGRAM(-1) - 1) + "()"
	
	DO CASE
		CASE VARTYPE(tuObj) == "O"
			? lcPrefix + "Object " + tuObj.Tag + " of type " + tuObj.Class + " in " + lcProc
			
		CASE VARTYPE(tuObj) == "C"
			? lcPrefix + "Procedure " + lcProc + ": " + tuObj
		OTHERWISE
			? lcPrefix + "Procedure " + lcProc
	ENDCASE
ENDPROC

DEFINE CLASS Chatty AS Custom
	ioChild = .NULL.

	PROCEDURE Init
		this.Tag = SYS(2015)
		Talk(this)
		this.AddObject("oChild", "nested")
	ENDPROC

	PROCEDURE Destroy
		Talk(this)
	ENDPROC
	
	PROCEDURE Test
		Talk("Begin")
		
		LOCAL lcType AS String, lcMember AS String
		
		lcMember = "this.ioChild.Parent"	&& Hang
		*lcMember = "this.oChild.Parent"	&& Ok
		
		lcType = TYPE(lcMember)
		Talk("Type of [" + lcMember + "] is: " + lcType)
		
		Talk("End")
	ENDPROC

	PROCEDURE ioChild_Access
		Talk(this)
		RETURN this.oChild
	ENDPROC
ENDDEFINE

DEFINE CLASS Nested AS Custom
	PROCEDURE Init
		this.Tag = SYS(2015)
		Talk(this)
	ENDPROC

	PROCEDURE Destroy
		Talk(this)
	ENDPROC
ENDDEFINE 

RE: Hanging object reference from trifecta of Type(), _Access(), and .Parent [SOLVED]

I spent a decent amount of time tracking down a similar bug and your post was instrumental in finding it! I've reworked your demo to show the situation that was causing dangling object references in my scenario.

For me it was a combination of the _Access method and storing a reference to the parent of the object reference returned from this accessor in a local variable. See the code snippet below.

CODE --> FoxPro

CLEAR

Talk("DoDemo - Begin")
DoDemo()
Talk("DoDemo - End")

RETURN


PROCEDURE DoDemo
	Talk("Begin")
	
	LOCAL loObj AS Object
	loObj = CREATEOBJECT("Chatty")
	loObj.Test()
	
	Talk("End")
ENDPROC

PROCEDURE Talk
	LPARAMETERS tuObj
	
	LOCAL lcPrefix AS String, lcProc AS String
	lcPrefix = REPLICATE("  ", MAX(PROGRAM(-1) - 1, 0))
	lcProc = PROGRAM(PROGRAM(-1) - 1)
	
	DO CASE
		CASE VARTYPE(tuObj) == "O"
			? lcPrefix + "Object " + tuObj.Tag + " of type " + tuObj.Class + " in " + lcProc
			
		CASE VARTYPE(tuObj) == "C"
			? lcPrefix + "Procedure " + lcProc + ": " + tuObj
		OTHERWISE
			? lcPrefix + "Procedure " + lcProc
	ENDCASE
ENDPROC

DEFINE CLASS Chatty AS Custom
	ioChild = .NULL.
	
	PROCEDURE Init
		this.Tag = SYS(2015)
		Talk(this)
		this.AddObject("oChild", "Nested")
	ENDPROC

	PROCEDURE Destroy
		Talk(this)
	ENDPROC
	
	PROCEDURE Test
		Talk("Begin")
		
		LOCAL loParent AS Object
		LOCAL lcParentClass AS String
		
		*loParent = this.ioChild.Parent && Hangs
		*lcParentClass = loParent.Class
		
		lcParentClass = this.ioChild.Parent.Class
		
		Talk("End")
	ENDPROC
	
	PROCEDURE ioChild_Access
		Talk(this)
		RETURN this.oChild
	ENDPROC
ENDDEFINE

DEFINE CLASS Nested AS Custom
	PROCEDURE Init
		this.Tag = SYS(2015)
		Talk(this)
	ENDPROC

	PROCEDURE Destroy
		Talk(this)
	ENDPROC
ENDDEFINE 

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members! Already a Member? Login

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close