Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate

Retrieve Calling Object Name From Invoked Method


  • Please log in to reply
12 replies to this topic
  • Guests
  • Last active:
  • Joined: --
Is it possible to retrieve the calling object name from an invoked method?

I'm making a class that stores objects with given names. And I need to make a method that does something with the name so I need to retrieve the name of the object.

I know I can store names in the base object when creating child objects and retrieve the stored name when the method is called. But I'd like to know if there is a simpler way of doing it.

Hopefully this example tells what I'm trying to do.
oClass := new myClass
oClass.Add("NameA")
msgbox % oClass.NameA.GetName()		;<-- I'd like to make this yield oSubA, which is the calling object name 

Class myClass {

	Add(name) {
		this[name] := new this.mySubClass
	}
	
	Class mySubClass {
		GetName() {
			return this.name			;<-- how do I return the calling object name?
		}	
	}
}
Thanks.

mKnight
  • Members
  • 28 posts
  • Last active: Aug 19 2014 08:44 AM
  • Joined: 19 Oct 2011
I believe you want this

Class mySubClass {
      GetName() {
         return this.[color=red]__Class[/color]        ;<-- how do I return the calling object name?
      }


  • Guests
  • Last active:
  • Joined: --

I believe you want this

Class mySubClass {
      GetName() {
         return this.[color=red]__Class[/color]        ;<-- how do I return the calling object name?
      }

That yields myClass.mySubClass. Sorry there was a mistake in the question.

msgbox % oClass.NameA.GetName() ;<-- I'd like to make this yield oSubA, which is the calling object name

In the comment it says oSubA, but it should be NameA. I forgot to change the comment before posting. I hope this makes the question a bit clearer.

mKnight
  • Members
  • 28 posts
  • Last active: Aug 19 2014 08:44 AM
  • Joined: 19 Oct 2011
I hop this will help..

oClass := new myClass
oClass.Add("NameA")
msgbox % oClass.NameA.GetName()      ;<-- I'd like to make this yield oSubA, which is the calling object name 

Class myClass {

   Add(name) {
      this[name] := new this.mySubClass(name)
   }
   
   Class mySubClass {
   
		__New(objectName) {
			this.objectName := objectName
		}
		
		GetName() {
			return this.objectName         ;<-- how do I return the calling object name?
      }
	}
}


  • Guests
  • Last active:
  • Joined: --
Sorry, that is not what I'm looking for since the added name appears in for loops. I need to store various keys in it so there should not be any properties in the object.
oClass := new myClass
oClass.Add("NameA")

For k, v in oClass.NameA
	msgbox %k% : %v%	;<-- the name appears in for loops

Class myClass {

   Add(name) {
      this[name] := new this.mySubClass(name)
   }
   
   Class mySubClass {
   
      __New(objectName) {
         this.objectName := objectName
      }
      
      GetName() {
         return this.objectName         
      }
   }
}
That's why I wrote this,

I know I can store names in the base object when creating child objects and retrieve the stored name when the method is called.

But the base object members are shared by the added objects. So this doesn't work.
oClass := new myClass
oClass.Add("NameA")
oClass.Add("NameB")

msgbox % oClass.NameA.GetName()

Class myClass {

   Add(name) {
      this[name] := new this.mySubClass(name)
   }
   
   Class mySubClass {
   
      __New(objectName) {
         this.base.objectName := objectName
      }
      
      GetName() {
         return this.objectName         
      }
   }
}


jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009

But the base object members are shared by the added objects. So this doesn't work.

Class myClass {

	Add(name) {
		this[name] := new this.mySubClass(name)
	}

	Class mySubClass {

		__New(objectName) {
			if Not IsObject(this.base.objectName)
				this.base.objectName := []
			this.base.objectName[&this] := objectName
		}

		GetName() {
			return this.objectName[&this]        
		}
	}
}


  • Guests
  • Last active:
  • Joined: --
That's clever. Thanks.

  • Guests
  • Last active:
  • Joined: --
I'm now trying to clean up the stored names when the Remove method is used. And while I've been doing it, I encountered a problem which is not directly related to this question. But since it is necessary to know whether the stored name is cleaned or not, I'd like to ask why I cannot retrieve the added object address with the GetAddress method. Why does pNameA become empty?
oClass := new myClass
oClass.Add("NameA")
oClass.Add("NameB") 
pNameA := oClass.GetAddress("NameA")			;<-- this doesn't retreive the pointer. Why is it?
oClass.Remove("NameA")

msgbox % oClass.NameB.base.objectName[pNameA]   ;this is empty since pNameA is empty 

Class myClass {

   Add(name) {
      this[name] := new this.mySubClass(name)
   }
   Remove(name) {
	  ObjRemove(this.base.objectName, &this)	;<-- I'm trying to clean up the stored name
      ObjRemove(this, name)   
   }
   Class mySubClass {

      __New(objectName) {
         if Not IsObject(this.base.objectName)
            this.base.objectName := []
         this.base.objectName[&this] := objectName
      }

      GetName() {
         return this.objectName[&this]       
      }
   }
}


jethrow
  • Moderators
  • 2854 posts
  • Last active: May 17 2017 01:57 AM
  • Joined: 24 May 2009
pNameA := &oClass.NameA


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
In myClass.Remove(), this.base.objectName is the same as myClass.objectName and &this retrieves the address of the parent object, not the child object identified by name.

In mySubClass.__New(), this.base.objectName is the same as mySubClass.objectName.

Given that an child object's name is logically a property of the child object, it would be much more sensible to store the name in the child object. Why should it be skipped during enumeration (for-loop)? If your object represents an array of items (either sequential or associative) and you wish the for-loop to include only those items, there are multiple options:
[*:voodfqta]Keep a separate array of items in the child object, such as child.items. You can make child[key] refer to child.items[key] by using meta-functions. To make for key,value in child enumerate only the items, override the _NewEnum() method and just do return this.items._NewEnum().
[*:voodfqta]Override the _NewEnum() method to return a custom enumerator object which has the behaviour you want. It only needs to implement one method: Next().Note that in jethrow's example, the following lines are not necessary:
if Not IsObject(this.base.objectName)
   this.base.objectName := []
This is because this.base.objectName[&this] is evaluated as (this.base)["objectName", &this], which is treated as a "multi-dimensional array". See Arrays of Arrays for more detail.

Note also that when you do ObjRemove(this, name), the return value is this[name] prior to removal. This will probably do the job:
ObjRemove(myClass.mySubClass.objectName, &ObjRemove(this, name))


  • Guests
  • Last active:
  • Joined: --

pNameA := &oClass.NameA

Thanks, that works. I still wonder why the GetAddress() method doesn't work though.

Given that an child object's name is logically a property of the child object, it would be much more sensible to store the name in the child object. Why should it be skipped during enumeration (for-loop)?

Thanks for the detailed answer. I'm writing a menu wrapper class that stores menu names as the keys. So if there is a menu named objectName in this case, the stored values may be lost or mixed with the menu object. I even having troubles with the base object key name, base, for this reason.

If your object represents an array of items (either sequential or associative) and you wish the for-loop to include only those items, there are multiple options:
[*:14sjf2sj]Keep a separate array of items in the child object, such as child.items. You can make child[key] refer to child.items[key] by using meta-functions. To make for key,value in child enumerate only the items, override the _NewEnum() method and just do return this.items._NewEnum().
[*:14sjf2sj]Override the _NewEnum() method to return a custom enumerator object which has the behaviour you want. It only needs to implement one method: Next().

This is intriging. I'll try overriding the _NewEnum() method. I haven't found a good example of it yet.

Note that in jethrow's example, the following lines are not necessary:

if Not IsObject(this.base.objectName)
   this.base.objectName := []

This is because this.base.objectName[&this] is evaluated as (this.base)["objectName", &this], which is treated as a "multi-dimensional array". See Arrays of Arrays for more detail.

I see. Thanks for mentioning it. It is same as,
obj := {}
obj.child["key"] := "aaa"
msgbox % obj.child["key"]	;yields aaa

Note also that when you do ObjRemove(this, name), the return value is this[name] prior to removal. This will probably do the job:

ObjRemove(myClass.mySubClass.objectName, &ObjRemove(this, name))

I've never thought about it. Many thanks.

  • Guests
  • Last active:
  • Joined: --
I found using the destructor is simpler.
oClass := new myClass
oClass.Add("NameA")
oClass.Add("NameB") 
pNameA := pNameA := &oClass.NameA	
oClass.Remove("NameA")
msgbox % oClass.NameB.base.objectName[pNameA]	; yields empty value which means the stored information has been cleaned

Class myClass {

   Add(name) {
      this[name] := new this.mySubClass(name)
   }

   Class mySubClass {
      __New(objectName) {
         this.base.objectName[&this] := objectName
      }
      __Delete() {
         ObjRemove(myClass.mySubClass.objectName, &this)
	  }
      GetName() {
         return this.objectName[&this]       
      }
   }
}


Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006

I still wonder why the GetAddress() method doesn't work though.

I still wonder whether you read the description of GetAddress in the manual.