Feature - Rejected ASH command for detecting if function defined

Theraze

Active member
I was pondering about whether or not something similar to the following C code was possible with ASH:
Code:
#if !defined(sample_function)
sample_function();
#endif
Basically, this would be so that in the cases of scripts using nearly idential functions, they can use the function defined in the other. It would likely get called mostly in terms of sanity checks... since abs() was the function that made me ponder this, the sample code following to see if abs needs to be redefined would work:
Code:
if (!defined(abs))
abs(int a){
    if(a<0) return -a;
    return a;
}
else if (abs(-5) != 5){
    print("Conflict with another script using the abs function. Stopping script.");
    exit;
}
If this can't happen, so it goes. Just thought that something like this may be useful for those who write scripts that have to play nice with others. :)
 

heeheehee

Developer
Staff member
Just a few notes:
I'm pretty sure function-name collisions usually only occur when one script is importing two or more other scripts. As you can see, order does matter:
Code:
> ash import <zlib.ash>; import <datelib.ash>

Function     'abs( int )' defined multiple times (datelib.ash, line 15)
Returned:     void

> ash import <datelib.ash>; import     <zlib.ash>;

Function 'abs( int )'     defined multiple times (zlib.ash, line 14)
Returned: void
(abs() inserted back into DateLib for testing purposes only; this should not be an issue with the latest version, since the latest version imports ZLib.)

Basically, as each new script is imported, its functions get added to the namespace. If, say, DateLib used defined() but ZLib doesn't, then the error might still crop up, depending on the order in which the scripts are imported.

So either:
a) both scripts would need to use defined(), or
b) the scripts that don't use defined() would have to be imported first.

This is potentially problematic, and very well might clutter a script excessively.
 

fronobulax

Developer
Staff member
I understand the problem, but I have been burned by conditional compilation in C enough times that I'd rather have the current situation. The basic issue is that you do not know, during static analysis, which version of a function was actually compiled and used, and there is no way to ensure that all possible versions yield the same code. If commenting out code in a text editor wasn't such an easy solution, I might change my mind.
 

heeheehee

Developer
Staff member
Also, another thing that'd be problematic is that ASH has curly-brace scope. Observe:
Code:
> ash if(4>2) {int f(int g) {return g+4;} print(f(7));}

11
Returned: true

> ash if(4>2) {int f(int g) {return g+4;}} print(f(7));

Function 'f( int )' undefined. This script may require a more recent version of KoLmafia     and/or its supporting scripts. ()
Returned: void

An interesting solution would be to apply some sort of stamp to the functions of a script, which would then be accessed via some ASH function. Doesn't seem particularly practical, of course, that's the problem with most solutions to this problem.

The best we can do in the meanwhile is to have scriptwriters work out stuff like this. (Dibs on boolean heartattack (int num, string player)!)
 

Theraze

Active member
Yeah... that's why I threw the check to make sure that abs() gave the same value... for that matter, in your testing of abs... if you changed datelib to use n as its value instead of a, so that they're both defined the same... does it still error?

Basically, what I'm wondering is whether there's any good way, without erroring, to allow for scripts to be more easily used with others... but not necessarily needing them if they aren't available.

Don't know if anyone has done a semi-limited release script similar to dj_d's ascend scripts where different people might have different files available that interact with each other (and other people's scripts). Parallel tracking of changes and fixes isn't exactly the best way to make sure that everything gets handled in a complete way.

Edit:
Tested and it does error, even though it's not a redefinition. Not sure if that's exactly as planned. Errors even when I copy-paste the zlib abs() over the old datelib one.
On a sidenote, replaced my old datelib script with the new one. :)
 
Last edited:

heeheehee

Developer
Staff member
It technically is a redefinition, as there's no way to distinguish which of the two to use -- both take the same parameter (int). I guess a slightly better solution would be to rename the function to something like "absval(int a)", but mmft. Arguable.
 

fronobulax

Developer
Staff member
It occurs to me that Perl and PHP both have to deal with this kind of collision or multiple definition issue and as scripting languages, they might have a solution that made sense in the context of Ash. Does anybody know how they do it or is that a research project?
 

Theraze

Active member
Apparently the Perl equivalent is "defined()", like C... http://perldoc.perl.org/functions/defined.html
Perl one basically runs the way that C does, and allows for unsetting previously set variables or functions if you need to.

PHP is confused, with 3 different checks: "isset()", "empty()", and "is_null()"... http://www.danielnorton.com/nerd/code/php/isdef
isset returns TRUE if a variable has been set to anything besides NULL.
empty returns TRUE if a variable doesn't have anything major in it. An empty string does not trigger a false on this.
is_null returns TRUE if a variable has not been set to anything besides NULL.

Basically, isset and is_null both return converse results... isset, in the examples given at least, != is_null.
 

xKiv

Active member
perl has had modules (namespaces) for decades
php got namespaces in version 5, I think

ETA:
Apparently the Perl equivalent is "defined()", like C... http://perldoc.perl.org/functions/defined.html
Perl one basically runs the way that C does, and allows for unsetting previously set variables or functions if you need to.

PHP is confused, with 3 different checks: "isset()", "empty()", and "is_null()"... http://www.danielnorton.com/nerd/code/php/isdef
isset returns TRUE if a variable has been set to anything besides NULL.
empty returns TRUE if a variable doesn't have anything major in it. An empty string does not trigger a false on this.
is_null returns TRUE if a variable has not been set to anything besides NULL.

Basically, isset and is_null both return converse results... isset, in the examples given at least, != is_null.

1) that "C" solution actually isn't C at all, it's preprocessor; and the preprocessor doesn't know that a function was defined; you have to explicitly define a preprocessor macro in the included file and then know which macro it is to test it ... and then be aware that the macro will F you UBAR like that "sugar alias" incident.
2) those "defined" and "isset" are not for functions, they are for testing if a value has been set to a variable ... you can only unset a function if you assigned it to a variable, but then you can just overwrite it with another (and probably anonymous) function without the language yelling at you anyway.
 
Last edited:
Top