Page 1 of 2

Inconsistent __Call behaviour

Posted: 07 Apr 2014, 04:56
by nnnik

Code: Select all

class TestClass{
__call(Name)
{
	Msgbox % Name
	return
}
TestMethod()
{
	Msgbox Fail
}
}

Class TestClass2 extends TestClass{
TestMethod2(){
Msgbox Fail	
}
}

Test:=new TestClass2()
test.TestMethod()
test.testMethod2()
We all agree that there should be two MsgBoxes each one displaying Fail.
But only the second Msgbox displays Fail.
I think this behaviour is inconsistent.

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 07:08
by Coco
If my understanding is correct, __Call always gets called prior to the actual method. Removing return allows it to proceed normally. Also, TestMethod() expects a msg argument, hence, (even if you remove return) it's not getting called.

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 07:13
by nnnik
No __Call is only called if there is no function with that name.
If 1 Msgbox shows a different Text than "Fail" then the behaviour differs from the one discribed in the Help File.
Also, TestMethod() expects a msg argument, hence, (even if you remove return) it's not getting called.
Oh right corrected tested no different result.

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 07:35
by Coco
No __Call is only called if there is no function with that name.
If 1 Msgbox shows a different Text than "Fail" then the behaviour differs from the one discribed in the Help File.

Code: Select all

class TestClass
{
	
	__Call(m, p*) {
		MsgBox, Called first even if method exists

	}

	method() {
		MsgBox, Hello World
	}
}

tc := new TestClass
tc.method()
return

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 07:57
by nnnik
ahkHelp wrote:Meta-functions are methods defined by an object's base which can define exactly how the object should act when an unknown key is requested. For example, if obj.key has not been assigned a value, it invokes the __Get meta-function. Similarly, obj.key := value invokes __Set and obj.key() invokes __Call.

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 08:05
by Coco
The derived object does not have the "method" key, so __Call gets called
e.g.:

Code: Select all

class TestClass
{
	__Call(m, p*) {
		MsgBox, Called first even if method exists
	}

	method() {
		MsgBox, Hello
	}
}
tc := new TestClass
tc.method() ; derived object calls method
TestClass.method() ; base object calls method

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 08:08
by nnnik
Then why isnt it called in an extended class?

Code: Select all

class TestClass{
__call(Name)
{
    Msgbox % Name
    return
}
TestMethod()
{
    Msgbox Fail
}
}

Class TestClass2 extends TestClass{
TestMethod2(){
Msgbox Fail 
}
}

Test:=new TestClass2()
test.TestMethod()
test.testMethod2()
Could be a bug.

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 08:13
by Coco
Removing or commenting out return does the trick:

Code: Select all

class TestClass{
__call(Name)
{
    Msgbox % Name
    ; return
}
TestMethod()
{
    Msgbox Fail
}
}

Class TestClass2 extends TestClass{
TestMethod2(){
Msgbox Fail 
}
}

Test:=new TestClass2()
test.TestMethod()
test.testMethod2()

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 08:15
by nnnik
Well it still doesnt call the __call function.
And thats wrong.

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 08:25
by Coco
Are you referring to testMethod2?

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 08:57
by nnnik
It is inconsitent meaning that either both (3 if you'd also take your example into consideration) boxes would show the Text "Fail" or their names.

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 11:39
by just me
Meta-functions are methods defined by an object's base which can define exactly how the object should act when an unknown key is requested. For example, if obj.key has not been assigned a value, it invokes the __Get meta-function. Similarly, obj.key := value invokes __Set and obj.key() invokes __Call.

In these cases, the base object is invoked as follows:
  • If this base object defines the appropriate meta-function, call it. If the meta-function explicitly returns, the return value is used as the result of the operation and no further processing occurs.
    Set: If the operation was successful, __Set should return the new value of the field, which may differ from the original r-value. This allows assignments to be chained, as in a.x := b.y := z. An empty string should be returned if the assignment failed, allowing the script to detect the error.
  • If this is a get or call operation, search for a matching key in the base object's own fields.
    Get: If found, the value of that field is returned.
    Call: If found, the function stored in the field (by name or reference) is called, passing the original target object as the this parameter.
  • Recursively invoke its own base object. This allows properties of an object to be "inherited" from its base, its base's base and so on.
Testclass doesn't have a base.
The base of Testclass2 is Testclass which defines a __Call meta-function.
The base of Test is Testclass2 which does not define a __Call meta-function.

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 11:55
by nnnik
That only explains why this happens, but the behaviour is still inconsistent - even if it is mentioned like that.
EDIT:
Topic was moved to Wish list at this point since just me has a point.
Workaround (THX @just me):

Code: Select all

class TestClass{
__call(Name) ;obsolete in the example
{
    Msgbox % Name
    return
}
TestMethod()
{
    Msgbox Fail
}
}

Class TestClass2 extends TestClass{
__call(Name)
{
    Msgbox % Name
    return
}
TestMethod2(){
Msgbox Fail 
}
}

Test:=new TestClass2()
test.TestMethod()
test.testMethod2()

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 12:14
by just me
I cannot see any inconsistency in this case. But I had some problems to comprehend this behaviour, too. ;)

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 20:51
by lexikos
What exactly is your "wish"?

If it confuses you, don't use it. Or at least don't mix __Call and normal methods in one class.

Re: Inconsistent __Call behaviour

Posted: 07 Apr 2014, 23:25
by nnnik
Towards me it seems more logical to call __call __get __set etc even if its only a part of the extended class.
But as you can see it has been solved since I moved it to Wish List.

Re: Inconsistent __Call behaviour

Posted: 08 Apr 2014, 00:24
by lexikos
So... why Wish List? It's no more a wish/feature/change request than it is a bug report.

Re: Inconsistent __Call behaviour

Posted: 09 Apr 2014, 14:09
by AfterLemon
__call is called each time a method within the class base is called. This ALWAYS happens.
If the class is an extension: obj.base.base, the prior base (obj.base) does not get called UNLESS the method does not exist in the extended class.

Code: Select all

class TestClass
{
	__call(MethodCall)
	{
		Msgbox,% MethodCall ".__call 1"
	}
	TestMethod(ClassName)
	{
		Msgbox,% ClassName ".Method 1"
	}
}

Class TestClass2 extends TestClass
{	
	__call(MethodCall)
	{
		Msgbox,% MethodCall ".__call 2"
	}
	TestMethod2(ClassName)
	{
		Msgbox,% ClassName ".Method 2"
	}
}

TestClass:=new TestClass()
TestClass2:=new TestClass2()
TestClass.TestMethod("TestClass")
Pause
TestClass.TestMethod2("TestClass")
Pause
TestClass2.TestMethod("TestClass2")
Pause
TestClass2.TestMethod2("TestClass2")
Pause

F1::pause
Am I totally missing the point here?

Re: Inconsistent __Call behaviour

Posted: 10 Apr 2014, 04:44
by HotKeyIt
TestClass has not got a method 'TestMethod2'.
the prior base does not get called UNLESS the method does not exist in the extended class
Do you mean in the class itself?

If obj has not got the method, obj.base is checked for the method, if not found there obj.base.base is checked ...
Finally if non of the objects has got that Method you will get the error message otherwise the Method would be called.

Code: Select all

class MainClass {
  __call(MethodCall){
      Msgbox,% MethodCall "`n__call MainClass"
  }
  MainCall(param){
    Msgbox,% "MainCall`nparam: " param
  }
}
class TestClass extends MainClass{
  __call(MethodCall){
    Msgbox,% MethodCall "`n__call TestClass"
  }
}
Class TestClass2 extends TestClass{
  __call(MethodCall){
    Msgbox,% MethodCall "`n__call TestClass2"
  }
}


TestClass2:=new TestClass2()

TestClass2.MainCall("test","param")
The method can be also a key where a function would be called dynamically:

Code: Select all

class MainClass {
  static MainCall:="MyFunc"
  __call(MethodCall){
      Msgbox,% MethodCall "`n__call MainClass"
  }
}
class TestClass extends MainClass{
  __call(MethodCall){
    Msgbox,% MethodCall "`n__call TestClass"
  }
}
Class TestClass2 extends TestClass{
  __call(MethodCall){
    Msgbox,% MethodCall "`n__call TestClass2"
  }
}
MyFunc(p*){
  MsgBox Function %A_ThisFunc% called
}

TestClass2:=new TestClass2()

TestClass2.MainCall("test","param")

Re: Inconsistent __Call behaviour

Posted: 10 Apr 2014, 12:58
by nnnik
So... why Wish List? It's no more a wish/feature/change request than it is a bug report.
Sorry for the long delay.
I posted it in Wish List since I understand how it works, and it isn't a bug since it works the way it is intended.
The "Wish List" section is a place where you put the requests to change the way it is intended, rather than notifying someone about a thing that does not work as intended.
That's why I moved it to "Wish List".