What if obj.nonEx does exist, but it invokes a property function or meta-function which accesses a non-existent property? It will throw an exception, which will likely bubble up to your exception handler, which may misinterpret it as meaning obj.nonEx does not exist. The exception object needs to identify the target object and missing property name. Then there's the less likely but still real possibility that the property is removed while it is executing, and invoked recursively (maybe indirectly). To get a truly accurate answer from the exception you need to verify the type of exception, the target object, property name and the call stack at the point the exception was thrown. This is very impractical; I think script authors are more likely to skip some of that, getting an ambiguous answer, like with unset only less efficient.Helgef wrote:For non-existent array elements, most often, an exception would be very helpful, it is very similar to call to non-existent method.
...
Especially for properties, a property get function might very well return something which is unset (perhaps by mistake, or perhaps not), it doesn't tell you anything about the existence of the property, an error does. We do not need unset for this, just an error.
The only way to get a clear answer (and easily) is to ask the object directly: theArray.has(i)? map.has(key)? node.hasProperty("textContent")?
Even without the ambiguity, I think that exceptions should not be used to represent conditions that are not errors. Using try-catch to find the answer to a question is incorrect if neither answer represents an error state. For instance, if you want to know whether a property exists, it is not an error for the property to not exist. a.nonEx can throw an exception, but only if accessing a non-existent property is always considered to be an error. In other words, either the property always exists, or the script is required to query its existence by some other mechanism before accessing it (or use some other access mechanism which does not treat non-existence as an error).
One (very much solvable) problem with adding exceptions for such things at this point is that there isn't yet an easy way to identify exceptions. That is, there isn't a proper system of exception types or any mechanism to filter based on type; or in other words, our exception system is incomplete. Completing it is not a priority for me, and if I still cared about getting v2.0 to a semi-stable (as in unchanging) state within a reasonable amount of time I probably would defer it to a later release. I might have never added exception handling at all if fincs hadn't developed it.
One of the reasons I sometimes prefer not to use exception-handling in scripts is that the syntax, while being very conventional, is very verbose. This could be counteracted with new syntax, such as the following loose ideas:
- Some form of inline try-catch expression, possibly allowing filtering by exception type.
- Success-or may.throw !|| errorExpression or success-conditional may.throw !&& successExpression / may.throw !? successExpression : errorExpression operators. (Or the opposite, with "exclamation" meaning "exception".) The main problem with this is the lack of exception type filtering.
On Error Resume Next
When this is used in a VB sub or function and an error (exception) occurs, execution resumes at the next statement - the one following either the statement that raised the error, or the statement that called out to some other procedure which raised the error. Err.Number and Err.Description contain information about the last error. It is much like AutoHotkey's use of ErrorLevel when calling certain built-in functions, but it is not limited to built-in functions. It is more like wrapping each line (statement) in try-catch, with the catch part merely storing the error information.
Err.Number is limited to identifying only the most recent error (like ErrorLevel), but we need not be limited in this way. There could instead (or in addition) be an array of all thrown values, which also implies an error count (the length of the array).
Unlike ErrorLevel, the error information may accumulate rather than reset after every successful function call, and it may be local to the function or block. Sometimes this would be much more convenient than exception handling, especially if one has to wrap each call in try-catch (and set the error flag, increment the error count or whatever).
Unlike VB's On Error or ErrorLevel, we could hypothetically allow filtering by the type of exception or other properties of the exception. The mechanism could allow for an expression or callback to be evaluated or called when an error occurs, prior to execution resuming. An example of where this could be used is:
Unlike the global OnError() callback, exceptions thrown by an interrupting thread would not reach this, just as it wouldn't reach another thread's try-catch.Helgef wrote:[...] I'd might want to set an onerror func at the start of a (probably complex) function, using a closure to clean up in case there was an error. Meaning I do not need to store a reference to the closure in the closure, which reduces the risk that I forget to break circular references.
Even if we are considering only control flow, not semantics, there is a big difference between the two. If one translatesnnnik wrote:Try & Catch vs If & Else. There is not much difference between the 2.
Code: Select all
If conditionalAction()
successAction()
else
failureAction()
; to
try {
conditionalAction()
successAction()
} catch
failureAction()
Another attempt at a solution might be to wrap successAction() in its own try-block, but then how do you throw the exception and ensure it won't be caught by the outer try?
So instead, one puts in the try block only the code whose exceptions should be handled by the catch block. The shortest I've come up with is:
Code: Select all
success := false
try conditionalAction(), success := true
if success
successAction()
else
failureAction()
It is code like the above that gave me the idea for inline-try (but success-or !|| also does the job):
Code: Select all
if try(conditionalAction()) ; or: if conditionalAction() !|| false
successAction()
else
failureAction()
Code: Select all
try:
conditionalAction()
catch:
failureAction()
else:
successAction()