Feature - Rejected NaN support in ASH

Veracity

Developer
Staff member
If we change Expression.eval() to make sqrt of a negative value use 1234.5678, we will never generate NaNs in Values. That will solve the root cause of your NPE.

I like it.
 

Catch-22

Active member
Veracity, I suppose you'll need to figure out what you really want.

Allowing script writers to write valid mathematical expressions such as:

> ash (((-1**0.5)**0)==1.0)

Returned: true


or, shielding script writers from the dark caress of imaginary numbers.

If it's the latter, then why were you so opposed to √-1 = 0?
 

heeheehee

Developer
Staff member
ASH doesn't support complex numbers. If it's that you want, I can write "complex.ash" :p (and yes, I will use an overly complicated representation of complex numbers, just so I don't have to write any custom handling)
 

Catch-22

Active member
Now that the actual bug is fixed, can we get a warning printed when modifier_eval returns a NaN?

In most cases I would say that a NaN return value is not expected, so a warning would be nice so the script writer can review.
 

Veracity

Developer
Staff member
Oh, we are not done. I am not convinced that allowing modifier_eval to return a NaN is appropriate for ASH. And "printing warnings" from library functions for script errors doesn't really fit the "style" of ASH.
 

heeheehee

Developer
Staff member
Out of curiosity, what exactly is the style of ASH?

In terms of language features, it certainly is imperative as well as strongly+statically-typed, but that certainly isn't enough to fully characterize a language. :) I'll take a stab at this question and call it a DSL (domain-specific language) for Mafia, which is in itself an interface (perhaps even an API) for KoL. However: if Mafia were just an API, then it would be as minimalist as possible, leaving all specifics to be implemented in ASH. Since not even knowledge of ASH's existence is necessary to use Mafia (i.e. a secondary interface is available to the end-user -- the GUI), this can't be the case... unless we want to start implementing the GUI details in ASH?

But no: obviously, that's not within the scope of ASH. The point of ASH, as far as I can tell, is to enable automation by asking Mafia about KoL (i.e. game details, character state). The point of automation is to reduce the need for human interaction. Printing warnings is therefore counter-intuitive.


... How far off am I?
 

Catch-22

Active member
And "printing warnings" from library functions for script errors doesn't really fit the "style" of ASH.

Not the style of ASH, but the style of modifier_eval. It already prints warnings when you do a malformed expression like "(", and returns 0.0. Are you going to change that behaviour also?
 

Veracity

Developer
Staff member
Not bad.

One thing to remember about ASH (the "Advanced Script Handler") is that it is, like the CLI, a "scripting language". Such languages execute commands or statements sequentially (modulo loops, function calls, and other control structures) until they either finish by "falling off the bottom of the script" or abort when any command or statement fails to "do the right thing".

Now, since ASH is a full programming language, we allow programs to "capture" requests to KoL that failed and continue execution. But library calls or operations that fail because of errors in the script - accessing a negative index in a string, dividing by zero, taking the square root of a negative number, and so on - throw runtime exceptions which will unwind the call stack, executing "finally" blocks, and exit the script with an error message, pointing out the erroneous file and line number.

It is not the "style" of ASH to simply print an error message and return a usable value to the script, allowing it continue executing with some arbitrary result.

Note the distinction between "capturing" an unexpected error from an interaction with KoL to avoid aborting the script and programming errors in the script that abort with no recourse. If a script aborts with a runtime error, the expectation is that the script needs to be fixed, rather than allowed to continue executing after a coding error generated an arbitrary or unreliable result.

The issue with modifier_eval/expression_eval is that their argument is, itself, a little program written in a specialized programming language, with the possibility of both syntax errors in the expression itself and runtime errors during the evaluation of the expression. Those functions are coded - and documented on the Wiki - as "always returning something, regardless of syntax errors or runtime errors."

I think it's time to revisit that, since both kinds of errors are, essentially, runtime errors in the script that calls modifier_eval/expression_eval, and should behave like other runtime errors caused by script errors, rather than failed interactions with KoL: they should throw a runtime error and require the script author to fix it.

THAT would be in the "style" of ASH.

My opinion. Which, I hope, counts for something. Not that KoLmafia is a democracy. :)

Not the style of ASH, but the style of modifier_eval. It already prints warnings when you do a malformed expression like "(", and returns 0.0. Are you going to change that behaviour also?
I'm leaning in that direction.
 

jasonharper

Developer
The problem with raising actual errors from modifier expressions is that they're being evaluated all the time - every time the character state changes in any way. Should a botched Candy Drop or some such expression be allowed to render the entire program unusable?
 

Veracity

Developer
Staff member
They are being evaluated all the time from ASH scripts? I am talking about changing the modifier_eval/expression_eval ASH functions to detect errors and throw exceptions on expression errors.

That has nothing to do with errors in built-in modifier expressions evaluated by other parts of KoLmafia - although it would be nice if those kinds of errors could get reported somehow.

Note that one way to do that is have an internal interface - Expression.eval1 - which throws exceptions.

Expression.eval calls that, traps exceptions, prints errors to the gCLI to help us debug our internal data files, and returns 0.0 to the internal KoLmafia caller.

RuntimeLibrary.modifier_eval and RuntimeLibrary.expression_eval call the eval1 versions, also trap exceptions, and throw ASH runtime errors to abort the script with filename and linenumber.
 
Last edited:
... we will never generate NaNs in Values.
Veracity said:
I like it.

This is exactly where I am. Instead of attempting to fix sortBy and map indices/values working on NaNs, it should just be downright impossible in ASH to even have a NaN to work with.

As for modifier_eval() breaking on string-to-number operations, ASH could either abort (put more work on the script author to make sure his math strings aren't malformed) which, hell, that's just good practice. Or, better yet, return an arbitrary number (0, please god, always 0) but give us a function that gives us information "last_mod_eval_fail()" or something to let us know if we can trust the number returned. Implemented NaN would be cool, and the math nerd in me would love it, but as pointed out in one of Veracity's numbered list, that's out of the scope of ASH.

Printing an error message and continuing on with an arbitrary value and no way for the SCRIPT to know that it's broken isn't useful to the myriad of people that use scripts for their main purpose: To get shit done when they aren't looking.
 

slyz

Developer
Or modifier_eval could() return a string, which could be tested with is_integer() or with is_float(), which we should add. For failed evals, it could simply print "fail", or something with informations.
 

Veracity

Developer
Staff member
Revision 11274 throws a runtime exception if the expression given to modifier_eval, monster_eval, or expr_eval has a parse error.

Revision 11275 throws a runtime exception if evaluating the expression attempts to divide by 0 or take the square root of a negative number.

There should no longer be a way for an ASH program to get its hands on a NaN. Therefore, rejecting this Feature Request as Unnecessary.
 

Veracity

Developer
Staff member
If you are absolutely set on banishing NaN from ASH entirely, you'll need to change the way arithmetic works in ASH generally, not just in Expressions

> ash (-1**1.5)

Returned: �
I'm sure what you MEANT to say (if you were generally trying to be helpful - or, perhaps, if you actually knew what you were talking about) was

Look at the ** operator. It calls Math.pow(), which can return a NaN.
Which is rather different than "the way arithmetic works in ASH generally".

Edit:

Revision 11290:

> ash (-1**1.5)

Taking a negative number to a non-integral power ()

Editorial comment:

So which is it: you are trying to be a know-it-all - or, perhaps, a dick - or you seek a place in my ignore list?

Frankly, I don't like your attitude. By all means - continue to contribute - but it will not be I who evaluates your contributions for inclusion in the codebase any more.
 
Last edited:

Catch-22

Active member
So which is it: you are trying to be a know-it-all - or, perhaps, a dick - or you seek a place in my ignore list?

It's just pretty late on my side of the world, I've been away from my computer for a week and I didn't feel very creative, so it's none of those.

I'll try to be a little more helpful this time.

pow can generate a NaN using positive/negative infinity (which should probably also not be allowed).

> ash (0.0**-1)

Returned: ∞

> ash (1**(0.0**-1))

Returned: �


> ash (-0.0**-1)

Returned: -∞

> ash (1**(-0.0**-1))

Returned: �


Edit: Also in my original post from whenever it was, by "generally" I meant that any special handling applied to Expressions should also be applied to ASH arithmetic operations (in this case **), I didn't mean any attitude. The post I wrote originally was before the patch to Expressions was applied, so it was more of a "heads-up if you're planning on fixing Expressions" than anything.
 
Last edited:

Catch-22

Active member
Awesome, this is fixed now. I'm not going to actively search for ways to generate NaN/Infinity values, so I'll post a new bug report if I ever come across one.
 
Top