"Script link failed: Runtime error: unresolved import ..."

Started by ArgyBoi, Sat 21/03/2015 22:12:18

Previous topic - Next topic

ArgyBoi

I know, I know, there are a bizillion threads talking about this error, but I couldn't find any that applies to my situation or with a solution that works for me. I've also checked the Wiki on scripting. So...
First, what I want to do is access a variable from a script (NOT a room script) that is declared in the global script. So I did this:

Code: ags

// GlobalScript.asc
int THING = 1;
export THING;


Code: ags

// GlobalScript.ash
// empty (I don't want to access THING from room scripts, so I don't have to import it here, right?


Code: ags

// AnotherScript.ash
import int THING;


Code: ags

// AnotherScript.asc
// ... some code ...
THING = 2;
// ... more code ...


The script order is:
AnotherScript
GlobalScript

The code compiles without any errors, but when I run the game, it crashes with the dialog "Script link failed: Runtime error: unresolved import 'THING'"

What I'm doing wrong?

PD: I'm using AGS 3.3.3.0

HandsFree

If you were to insist on using all that import/export you would have to declare the variable in the AnotherScript.asc because that one is called first.
But the Global Variables option is made specifically to avoid that (in the project explorer above the scripts).
So I recommend to use it and put all your global variables there. No import/export stuff needed anymore.

Crimson Wizard

You can't use a variable from lower script in the higher script. You simply can't.

It compiles without errors, simply because you declare such variable exists with "import". "Import" makes compiler trust that such variable will be availble. In your case, you "lied" to compiler, not provided actual variable, that would be available for higher script.

Snarky

Quote from: Crimson Wizard on Sun 22/03/2015 02:27:48
You can't use a variable from lower script in the higher script. You simply can't.

It compiles without errors, simply because you declare such variable exists with "import". "Import" makes compiler trust that such variable will be availble. In your case, you "lied" to compiler, not provided actual variable, that would be available for higher script.

I discovered an interesting wrinkle on this when refactoring some code. For a function, you would usually put the import statement in the header of the script that defines it. But you don't actually have to. As long as there is an import before you try to use it, it will be fine. For example, if I have three script modules: UsefulModule.acs, MagicModule.acs and DoStuff.acs, and there is a function called fixLights() in UsefulModule that is not declared in the header, but the MagicModule header for some reason says "import void fixLights();", then you can call fixLights() from DoStuff, and it will run the code in UsefulModule.

On the one hand, this does make sense in a way. On the other, I had gotten into the habit of thinking of my header as the API to the script, and believing that anything not declared there could not be accessed from outside it. (I haven't checked what happens if several scripts have "internal" methods by the same name - not unlikely in my case, I tend to reuse the same coding patterns with standard names - and you try to import one of them. Presumably a compiler or runtime error.)

ArgyBoi

Ok, thank for your replies! I'm aware of the Global Variables feature in the editor, but I didn't want to make that particular variable "global", and also I was hoping to apply the same principle to a non-managed type, so the Global Variable thing doesn't solve my problem in the end.
Anyway, I just coded it with a different approach to avoid the export/import thing.

Thanks!

monkey0506

Quote from: Snarky on Sun 22/03/2015 09:40:35I discovered an interesting wrinkle on this when refactoring some code. For a function, you would usually put the import statement in the header of the script that defines it. But you don't actually have to. As long as there is an import before you try to use it, it will be fine. For example, if I have three script modules: UsefulModule.acs, MagicModule.acs and DoStuff.acs, and there is a function called fixLights() in UsefulModule that is not declared in the header, but the MagicModule header for some reason says "import void fixLights();", then you can call fixLights() from DoStuff, and it will run the code in UsefulModule.

This is actually the expected behavior. imports don't even have to appear in a header (ever). IIRC it just simply imports the first matching definition. As an example, if ScriptA defines a function but does not have an import for the function in its header, then ScriptB may define an exactly identical function without causing any problems (as long as ScriptB's header similarly does not import the function). You could then have an import in ScriptC's header, ScriptC's main script file, or even in a room script file, and (again, IIRC) the import would refer exclusively to ScriptA's function and ignore changes to ScriptB's function. I believe that SSH encountered this with the BackwardsCompatibility module, where he inadvertently was pulling deprecated functions back into scope rather than redefining them (which was his original intention). Pumaman said that this was by-design (the deprecated functions just simply lack imports, but otherwise could be used at will).

The import may appear before or after the function, in any script or script header. If an import appears in a script header, then it will be included in all subsequent scripts (additional imports of the same item will cause an "already defined" compile error).

The imported item cannot be used in any script prior to its definition.

In a manner of speaking, you can think of import in AGS as being similar to C++'s extern, with the main difference being that AGS lacks proper forward declaration. Attempting to use the imported item before its full definition will cause a failure to link, and an "unresolved import" error. Understanding the difference between declaration and definition is helpful here, with a note that AGS doesn't allow you to use anything that isn't fully defined.

SMF spam blocked by CleanTalk