Inconsistent __Call behaviour

Propose new features and changes
User avatar
nnnik
Posts: 4470
Joined: 30 Sep 2013, 01:01
Location: Germany

Inconsistent __Call behaviour

07 Apr 2014, 04:56

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.
Recommends AHK Studio
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

Re: Inconsistent __Call behaviour

07 Apr 2014, 07:08

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.
User avatar
nnnik
Posts: 4470
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Inconsistent __Call behaviour

07 Apr 2014, 07:13

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.
Recommends AHK Studio
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

Re: Inconsistent __Call behaviour

07 Apr 2014, 07:35

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
User avatar
nnnik
Posts: 4470
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Inconsistent __Call behaviour

07 Apr 2014, 07:57

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.
Recommends AHK Studio
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

Re: Inconsistent __Call behaviour

07 Apr 2014, 08:05

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
User avatar
nnnik
Posts: 4470
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Inconsistent __Call behaviour

07 Apr 2014, 08:08

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.
Recommends AHK Studio
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

Re: Inconsistent __Call behaviour

07 Apr 2014, 08:13

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()
User avatar
nnnik
Posts: 4470
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Inconsistent __Call behaviour

07 Apr 2014, 08:15

Well it still doesnt call the __call function.
And thats wrong.
Recommends AHK Studio
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

Re: Inconsistent __Call behaviour

07 Apr 2014, 08:25

Are you referring to testMethod2?
User avatar
nnnik
Posts: 4470
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Inconsistent __Call behaviour

07 Apr 2014, 08:57

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.
Recommends AHK Studio
just me
Posts: 7224
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Inconsistent __Call behaviour

07 Apr 2014, 11:39

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.
User avatar
nnnik
Posts: 4470
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Inconsistent __Call behaviour

07 Apr 2014, 11:55

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()
Recommends AHK Studio
just me
Posts: 7224
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Inconsistent __Call behaviour

07 Apr 2014, 12:14

I cannot see any inconsistency in this case. But I had some problems to comprehend this behaviour, too. ;)
lexikos
Posts: 7057
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: Inconsistent __Call behaviour

07 Apr 2014, 20:51

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.
User avatar
nnnik
Posts: 4470
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Inconsistent __Call behaviour

07 Apr 2014, 23:25

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.
Recommends AHK Studio
lexikos
Posts: 7057
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: Inconsistent __Call behaviour

08 Apr 2014, 00:24

So... why Wish List? It's no more a wish/feature/change request than it is a bug report.
User avatar
AfterLemon
Posts: 83
Joined: 30 Sep 2013, 14:27
Location: Arizona, USA

Re: Inconsistent __Call behaviour

09 Apr 2014, 14:09

__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?
HOME: Windows 7 x64 SP1 Ultimate | AMD FX 8350 8-Core @ 4.00GHZ | 16GB Ram
WORK: Windows 7 x64 SP1 Home Premium | AMD Athlon II X4 640 @ 3.00GHz | 8GB Ram
MOBILE: Samsung Galaxy Note 3 | 2012 Asus Nexus 7 | Zune 80Gb
HotKeyIt
Posts: 2139
Joined: 29 Sep 2013, 18:35
Contact:

Re: Inconsistent __Call behaviour

10 Apr 2014, 04:44

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")
User avatar
nnnik
Posts: 4470
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Inconsistent __Call behaviour

10 Apr 2014, 12:58

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".
Recommends AHK Studio

Return to “Wish List”

Who is online

Users browsing this forum: No registered users and 5 guests