Error: No object to invoke

Discuss the future of the AutoHotkey language

Should this error be removed?

Poll ended at 27 Jul 2014, 10:57

No, keep it as it is
1
17%
Yes, revert back to return empty string
1
17%
Make it optional and return empty string by default
4
67%
Make it optional and throw error by default
0
No votes
 
Total votes: 6
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Error: No object to invoke

27 Jun 2014, 10:57

Code: Select all

MsgBox % obj.a.1
I would like to revert this change back to silently return empty string.
Otherwise a lot of code might be required and it gets very cumbersome.

Here one example in my case:

Code: Select all

; Before
If text:=ie.document.All[frame].ContentWindow.document.getElementByID(item).innertext
  ; ...

;Now if you don't like to get an error shown
If tmp:=ie.document.All[frame]
If tmp:=tmp.ContentWindow
If tmp:=tmp.document
If tmp:=tmp.getElementByID(item)
if text:=tmp.innertext
  ; ...
arcticir
Posts: 693
Joined: 17 Nov 2013, 11:32

Re: Error: No object to invoke

27 Jun 2014, 18:15

I agree with the recovery.

V2 now like disaster.


I use a lot of the structure of an object tree,
I had to use a lot of judgment, in order to prevent errors.

Code: Select all

if IsObject(HU) and IsObject(HU["/i/"]) and IsObject(HU["/i/"]["hy"])
          A:=HU["/i/"]["hy"]["locale"]
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: Error: No object to invoke

27 Jun 2014, 19:35

Code: Select all

; Before
If text:=ie.document.All[frame].ContentWindow.document.getElementByID(item).innertext
   ; ...

; After
Try {
   text:=ie.document.All[frame].ContentWindow.document.getElementByID(item).innertext
   ; ...
}
:?:
User avatar
RobertL
Posts: 546
Joined: 18 Jan 2014, 01:14
Location: China

Make it optional and return empty string by default

27 Jun 2014, 21:47

For case x:=a.b.d.e, I make a function used like this:

Code: Select all

if IsObjects(a,"b",c,"d")
    x:=a.b[c].d.e
To determine by internal iteration .
And

Code: Select all

if ObjectOrNull(a).b[c].d!=Null
    x:=a.b[c].d.e
Where Null is a supper-global currently.
(Code in IsObject() Extention with description in Chinese)

Also may extend IsObject to support Variadic, like IsObject(A,B,C) to determine if all params are object within one call.


I would like to return empty string means a warn (may use an ErrorLevel to describe more infomation), not an error.

Make it optional better, like #Warn and with defferent levels. Warn + Default handle / Error.
For example, Var:=None_Object.Key returns empty string, None_Object.Key:=Val/None_Object.Name() raise an exception, by default.
Last edited by RobertL on 28 Jun 2014, 03:29, edited 1 time in total.
我为人人,人人为己?
arcticir
Posts: 693
Joined: 17 Nov 2013, 11:32

Re: Error: No object to invoke

28 Jun 2014, 00:21

Try Not applicable.

Try Skip error。A AND B Not appear。

Code: Select all

Try {
	IF HU["i"]["hy"]["locale"]
	MsgBox,A
	else
	MsgBox,B
}
Want to achieve the effect of the original。
This destroys the structure of the script。

Code: Select all

Try {
	IF HU["i"]["hy"]["locale"]
	MsgBox,A
}catch{
	MsgBox,B
}
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
Contact:

Re: Error: No object to invoke

28 Jun 2014, 01:08

arcticir wrote:Try Not applicable.

Try Skip error。A AND B Not appear。

Code: Select all

Try {
	/* this expression checks if 'locale' key resolves to 'true' or  'false'
	 * should 'HU["i"]["hy"]' return an object, the entire block will be
	 * executed. IMO, in this scenario, 'try' is not being used as the way
	 * it should be.
	 */
	IF HU["i"]["hy"]["locale"]
	MsgBox,A
	else
	MsgBox,B
}
I'm fine with the current behavior as it helps user(s) write clean and bug-free code. Making it optional is fine as well.
User avatar
RobertL
Posts: 546
Joined: 18 Jan 2014, 01:14
Location: China

Re: Error: No object to invoke

28 Jun 2014, 01:32

arcticir wrote:Try Not applicable.
Try Skip error。A AND B Not appear。

Want to achieve the effect of the original。
This destroys the structure of the script。
When error/exception happened in Try statements, the flow of execution goto Catch, like if(false) then else..
if..else belongs to User's designed logic, and Try..catchis unexcept execution have to fix.
Otherwise, use try{..}catch{..}, like if(..){..}else{..}.
Last edited by RobertL on 28 Jun 2014, 03:26, edited 1 time in total.
我为人人,人人为己?
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: Error: No object to invoke

28 Jun 2014, 02:35

Try is useful in many cases but often it creates to much code, especially duplicated MsgBox 2 in that case is a pain :(

Code: Select all

;Before 2 lines
If obj.a.1=0,Msgbox 1
else MsgBox 2

;Now 6 lines and duplicated code
try {
  if obj.a.1=0
    MsgBox 1
  else MsgBox 2
} catch 
  MsgBox 2

;Now we could also use a variable to reduce code but that is not good practice I think
try result:=obj.a.1
If result, MsgBox 1
else MsgBox 2
We need a #Warn to get an error for variables, so why not do the same for objects?

Code: Select all

#Warn
If var
  Msgbox
User avatar
RobertL
Posts: 546
Joined: 18 Jan 2014, 01:14
Location: China

Re: Error: No object to invoke

28 Jun 2014, 03:49

@HotKeyIt
HotKeyIt wrote:

Code: Select all

try {
  if obj.a.1=0
    MsgBox 1
  else MsgBox 2
} catch 
  MsgBox 2
Cleaner:

Code: Select all

try{
  if c
    s1  ;c is true
  else
    s2  ;c is false
}catch
    s3 ;handle error in c/s1/s2 etc.
The method and extra code is choosen up to the user.
if..else belongs to User's designed logic, and Try..catch is unexcept exception have to face.
Exception is a new level of exectution flow.
See post above.

My brief opinion:
Warn infomation (ErrorLevel) + Defalut handle (return empty string), or Error (throw exception).
Use different level on Warn/Error.
See post above.
Last edited by RobertL on 28 Jun 2014, 04:04, edited 3 times in total.
我为人人,人人为己?
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
Contact:

Re: Error: No object to invoke

28 Jun 2014, 03:57

@HotKeyIt
The MsgBox 2 under catch is meant to be shown if obj.a is not an object which is different from the purpose of MsgBox 2 inside the try block which is meant to be shown if obj.a.1 is not equal to 0. Try/Catch/(Finally) should be used for runtime error(s)/exception(s) not for logical/boolean expressions. I think it's better to do IsObject(obj.a) / if obj.a is 'object' rather than assuming it as one and invoking it, hence, the need for try and/or catch.
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: Error: No object to invoke

28 Jun 2014, 11:35

Coco wrote:@HotKeyIt
The MsgBox 2 under catch is meant to be shown if obj.a is not an object which is different from the purpose of MsgBox 2 inside the try block
I think in most cases it is not different for the user, we all use it in v1 and I have never seen a request to implement something like this, also nobody ever requested to have #Warn by default.

I have been using v2 for 2-3 years now and never found need for it, and as you see in the first post I even did not use it when I needed it. Btw. this is the only function where I get this error.
I fully agree it is a useful feature, but definitely it shouldn't be the default behavior and will be a pain for every beginner.
Another example, as you see 1 line is now at least 4 lines :(

Code: Select all

;Before
If !obj.item.value, obj["item","value"]:="default"

; Now we are forced to duplicate the code
try 
  If obj.item.value="",obj["item","value"]:="default"
catch
  obj["item","value"]:="default"
My logic works rather like this, expecially because I don't need catch here. Even when not using try catch as in this example, in most cases we will have to duplicate the code which gets quickly bulky and complex.
Imagine you have a nested if..else that is 10 lines, using try catch there will be at least 40 lines, rather more. How is this helpful?

Code: Select all

If !IsObject(obj.item),  obj.item:=["default"]
else If !obj.item.value,  obj.item.value:="default"
Btw. I feel the same for all exception errors.
I think it would be best to have it optionally and let user decide whether to throw an exception but set ErrorLevel by default.

Another example, here I need to take the same action when a file is old or it does not exist:

Code: Select all

; Before
If FileGetTime(file)<SubStr(A_Now,1,8) "000000"
  ...

; Now
If !FileExist(file) || FileGetTime(file)<SubStr(A_Now,1,8) "000000"
 ...
Also I think the error should show which object could not be invoked, otherwise it is not very helpful, e.g.: obj.item.sub.1.name.

Can anyone show a few examples where it would be useful for a beginner? So something where it is really important to use catch?
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
Contact:

Re: Error: No object to invoke

28 Jun 2014, 13:08

Using the new behavior of OR/||, you can avoid the exception and also won't need try:

Code: Select all

obj := {item:""} ; item does not contain an object, 'obj.item.value' should throw an error 
if (obj.item || obj.item:=[]).value, obj.item.value := "default"
else obj.item.value := "some value"
MsgBox % obj.item.value
However, this will be too cumbersome for nested objects.

I'm OK with allowing it as an optional feature.
User avatar
RobertL
Posts: 546
Joined: 18 Jan 2014, 01:14
Location: China

28 Jun 2014, 21:39

HotKeyIt @Coco
When read a key of none_object. Its defalut handle could return empty string (not necessary to raise an exception).
Such as, var=none_object.key doesn't cause error on compile, but none_object.key=val should.
The runtime error should work in accordance with compile-time error, I think.
At least, %x%:=val/var:=%x% will raise an runtime error, should this be skipped? I don't think so.

Code: Select all

If obj.item.value=""
The true condition here actually contains three part: the objnot exist, the value of obj.item not exist, or the value of obj.item.value is "".
Similar case, if a.b!=d, the true condition contains three part.
Another case, If a.b=d, the true condition is only: a is an object, b is its key, and the value of a.b is d.
The default behaviour of returning empty string when access none_object as object, import extra condition!
If it is designed for this( a may be none_object, b may not be a key in a, the value of a.b may not equal d), thus determine them separately.

Use A[b,c,d,..] instead of A.b.c.d... will automatically support Multi-dimensional assignments (in Arrays of Arrays on Help), I think.
A.B.C.D.. equals _1:=A.B, _2:=1.C, _3:=2.D, ...



Many steps are necessary, may be they could integrated in user-define function, with less code to do the same thing.
Like IsObjects/IsObject(A,B,C).
There may be a lot of conditions, I blame the problem for complex design.

Also I agree that, the error in Errorleve should show which object could not be invoked.

For beginner.
I think AHK better handle error default, prompt out various cases and hint user to decompose the complex problems, ask them how would they like to deal with the problem when the object read/write/call operate can't work on a none_object? Perhaps they just want to keep it, but now skip.

Now I only use exception to get extra error infomation besides ErrorLevel.

I'm OK with allowing it as an optional feature, too.

I find a rough way to use try..catch.
Associate the try..catch like labels. Use like this:

Code: Select all

Try1
If C
Catch1:
   ...
Now they could (re)use the same code.
Otherwise, disable and skip the error/keep going on next code temporarily?

Another way, use Default Base Object of string! (See Objects \ Custom Objects \ Default Base Object in help)
"".base.__Set := Func("...")

总结见关于设计,错误/异常处理
Last edited by RobertL on 29 Jun 2014, 07:37, edited 13 times in total.
我为人人,人人为己?
jaco0646
Posts: 10
Joined: 17 Oct 2013, 19:28

Re: Error: No object to invoke

28 Jun 2014, 22:51

Groovy added the so-called safe navigation operator ?. to avoid the verbosity of null checks and try/catch that pervades Java.

http://groovy.codehaus.org/Operators#Op ... onOperator(?.)
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
Contact:

Re: Error: No object to invoke

28 Jun 2014, 23:39

RobertL wrote:The runtime error should work in accordance with compile-time error, I think.
This might be difficult to implement for this specific scenario...I don't know, maybe it's doable, it would be nice though.
RobertL wrote:I find a rough way to use try..catch.
Associate the try..catch like labels. Use like this:
It'll complicate it more, I guess. The user can write something like:

Code: Select all

assert(args*) {
    try ...
    catch ...
    finally ...
}
Perhaps #ErrorStdOut should catch these as well instead of always showing a MsgBox()
Returning an empty string will leave user(s) clueless on whether the call succeeded or not, unless ErrorLevel gets set every time it fails.
User avatar
RobertL
Posts: 546
Joined: 18 Jan 2014, 01:14
Location: China

Re: Error: No object to invoke

29 Jun 2014, 00:15

Coco wrote: @Coco
I update my point and code in the latest one above. I think it's more persuasiveness and mature.
See a.b!=d / a.b=d / a.b="" and Default Base Object.
I will keep and then hide this post a little while.
我为人人,人人为己?
lexikos
Posts: 9553
Joined: 30 Sep 2013, 04:07
Contact:

Re: Error: No object to invoke

29 Jun 2014, 06:04

HotKeyIt wrote:We need a #Warn to get an error for variables, so why not do the same for objects?
I presume you're referring to the "uninitialized variable" warnings. Using the value of an uninitialized variable isn't considered to be an error in most cases; the warning is just a tool for debugging. ("Uninitialized" variables really are initialized, just not by the script itself.) This doesn't apply in the same way to objects - When you invoke x.y, you're asking for something to be done with the object contained by x. If x doesn't contain an object, what you're asking for simply can't be done.

Invoking an object is an operation, like calling a function or double-dereferencing. Invalid double-derefs and dynamic calls also cause exceptions.
Coco wrote:I think it's better to do IsObject(obj.a) / if obj.a is 'object' rather than assuming it as one and invoking it,
I agree. Invoking an object which doesn't exist shouldn't be treated as a valid thing to do.
HotKeyIt wrote:I fully agree it is a useful feature, but definitely it shouldn't be the default behavior and will be a pain for every beginner.
Errors and invalid operations which leave no trace are a pain for everyone.
Another example, as you see 1 line is now at least 4 lines :(
Both your 1 line code and your 4 line code assume obj is an object. Therefore, you could easily write it in one line with only a minor change from your original code:

Code: Select all

if !obj["item","value"], obj["item","value"]:="default"
This is also more symmetrical (using the same syntax for both operations), so I would prefer to write it this way in the first place.
; Now we are forced to duplicate the code
That is one way, but very rarely the only option. It's often not even the easiest.
I think it would be best to have it optionally and let user decide whether to throw an exception but set ErrorLevel by default.
I had already decided against implementing that sort of "error switch" in general. Encouraging users to be lazy causes more problems down the track. Treating things as valid with an optional warning is better, but only where convenience outweighs the potential debugging headaches.

Furthermore, general operations within expressions should not set ErrorLevel.
Another example, here I need to take the same action when a file is old or it does not exist:
FileGetTime() doesn't throw an exception in the current alpha. I don't see why your old code wouldn't continue to work.
Also I think the error should show which object could not be invoked, otherwise it is not very helpful, e.g.: obj.item.sub.1.name.
That isn't technically possible, because there is no object; that's the point. You probably mean "which part of the expression", but that also isn't technically possible at the moment. I think I initially designed it to display the target value (which is not an object), but since the value is generally an empty string (which gives exactly the same result as now), I thought it better to omit that code.
Can anyone show a few examples where it would be useful for a beginner? So something where it is really important to use catch?
It is not "really important to use catch". It is important to validate what you're doing before you do it. It is better to avoid causing errors than to react to them. It is important to avoid introducing hard-to-detect bugs (e.g. by ignoring errors or pretending they are valid).
RobertL wrote:Also may extend IsObject to support Variadic, like IsObject(A,B,C) to determine if all params are object within one call.
IsObject already behaves like that. It can't be used in the manner you are thinking of because A, B and C each need to be fully evaluated before IsObject is called. For example, IsObject(x.y, x.y.z) will cause an error if x.y is not an object, because x.y.z is evaluated before IsObject is called.


Note: The current behaviour is not necessarily final. I am simply not convinced that it should be changed.
User avatar
RobertL
Posts: 546
Joined: 18 Jan 2014, 01:14
Location: China

Re: Error: No object to invoke

29 Jun 2014, 07:03

lexikos wrote:
RobertL wrote:Also may extend IsObject to support Variadic, like IsObject(A,B,C) to determine if all params are object within one call.
IsObject already behaves like that. It can't be used in the manner you are thinking of because A, B and C each need to be fully evaluated before IsObject is called. For example, IsObject(x.y, x.y.z) will cause an error if x.y is not an object, because x.y.z is evaluated before IsObject is called.
Oh, it seems that the instruction of IsObject doesn't mention the behavies above in help.
And yes, I knew the manner. I mean I create a function IsObjects to determine A.B.D by internal iteration, like IsObjects(A,"B",C,"D").
I quite agree with you. :)
My major point at post above. Entreat your guide :roll:
我为人人,人人为己?
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: Error: No object to invoke

29 Jun 2014, 17:10

Thanks for explanation lexikos.
I did not realize that obj["item","value"] won't trow an exception and I have also missed that File commands do not throw exception anymore, thanks for pointing out.

I think it is really important to show the part of expression that fails, we could for example backup this_token.deref in g->ExcptDeref before the function is called in ExpandExpression and use it when exception is thrown. I did run a few test and it shows the right information.

Code: Select all

	if (aResult == INVOKE_NOT_HANDLED)
	{
		// Invocation not handled. Either there was no target object, or the object doesn't handle
		// this method/property.  For Object (associative arrays), only CALL should give this result.
		if (!obj)
			aResult = g_script.ThrowRuntimeException(ERR_NO_OBJECT, NULL, g->ExcptDeref ? g->ExcptDeref->marker : _T(""));
		else
			aResult = g_script.ThrowRuntimeException(ERR_NO_MEMBER, NULL, aParamCount && *TokenToString(*aParam[0]) ? TokenToString(*aParam[0]) : g->ExcptDeref ? g->ExcptDeref->marker : _T(""));
	}
arcticir
Posts: 693
Joined: 17 Nov 2013, 11:32

Re: Error: No object to invoke

07 Jul 2014, 22:01

@Lexikos
Can you help me look at the following script how fast and simple to complete it?

Code: Select all

HU:=CriticalObject()  		; Global Object 
HU.INI:=IniToObj("hy.ini")  	; Not sure this file Whether exists, So do not know HU.INI whether is object.


; And in this case I frequently read HU.INI:


locale:=HU.INI.HY.locale?HU.INI.HY.locale:"EN"  ; Uncertainty  Section (HY) whether there

;...

Run, % (HU.INI.Browser.Chrome?HU.INI.Browser.Chrome:HU.INI.Browser.Opera?HU.INI.Browser.Opera:"") " " (HU.INI.ip.google?HU.INI.ip.google:"www.google.com")

;...

for i in HU.INI.Module
	Load(i)

;...

if  ErrorLevel
	SoundBeep, 750, 500
else if IsLabel(HU.INI.Music.gh)
	Gosub, % HU.INI.Music.gh
;...

a:=HU.INI.Wallpaper.Switch 
	? (HU.INI.System.Wallpaper=1 
		? HU.INI.Wallpaper.Path1
		: HU.INI.Wallpaper.Path2)
	: ""

; more Hundreds

I do not care INI Section Whether there,do not care INI.Section Whether it is an object
I do not want a lot of use IsObject()
I just want to write code fast and simple
Will this case, how to complete it?

Thanks.

Return to “AutoHotkey Development”

Who is online

Users browsing this forum: No registered users and 40 guests