"Access a non-static member" error with static attribute

Started by Snarky, Sat 07/10/2017 14:08:18

Previous topic - Next topic

Snarky

I have some Character* variables in a module script that I need to expose, but that I would like to stay read-only outside of the script. To that end, instead of just exporting the variables globally, I'm trying to put them as static attributes inside of a struct, with getters that return the script-local values:

Code: ags
struct MyModule
{
  import static readonly attribute Character* ActiveCharacter;  // $AUTOCOMPLETESTATICONLY$
  import static Character* get_ActiveCharacter();               // $AUTOCOMPLETEIGNORE$
};


Implemented in the script as:

Code: ags
Character* _activeCharacter;
static Character* MyModule::get_ActiveCharacter()
{
  return _activeCharacter;
}


However, when I try to actually refer to this character, I get a compilation error:

Code: ags
  MyModule.ActiveCharacter.Say("Blah blah"); // Fails to compile


"must have an instance of the struct to access a non-static member"

It works (or at least, it doesn't throw a compilation error: I haven't been able to test it live) if I instead write:

Code: ags
  Character* c = MyModule.ActiveCharacter
  c.Say("Blah blah");


However, that is massively less convenient, and makes the whole approach pretty much useless for me.

It seems to be related to this bug: http://www.adventuregamestudio.co.uk/forums/index.php?topic=32083.0

Is there any way around this or some way to fix it?

monkey0506

The only workaround presently is to not use static attributes.

Code: ags
struct MyModule_t // renamed, because we have to use an instance rather than statics
{
  import readonly attribute Character* ActiveCharacter;
};

import MyModule_t MyModule; // import the instance


Code: ags
MyModule_t MyModule;
export MyModule;

Character *_activeCharacter;

Character* get_ActiveCharacter(this MyModule_t*) // switched to extender just to avoid having to rely on $AUTOCOMPLETEIGNORE$, functionally the same
{
  return _activeCharacter;
}


Code: ags
MyModule.ActiveCharacter.Say("Blah blah");


This is the method I used in the latest ScrollingDialog module, for example, to achieve such feats as:

Code: ags
ScrollingDialog.ScrollArrows.Up.Padding.Bottom = 2;


It is a hassle to not be able to take full advantage of static attributes, but that's the current situation.

Snarky

Thanks! That's essentially what I ended up doing, though your version is nicer, with the naming scheme mimicking a static class and the extender trick (I didn't know you could use extenders as attribute accessors).

monkey0506

Quote from: Snarky on Mon 16/10/2017 08:03:52the extender trick (I didn't know you could use extenders as attribute accessors).

Yeah, the way extender methods inject themselves means they are exactly the same as standard struct methods, even down to ridiculous and unnecessary definitions like:

Code: ags
import void Scream(this Character*); // imported using extender method syntax

void Character::Scream() // defined using standard method syntax
{
  this.Say("AHHHHHH!");
}


The engine and compiler don't make any distinction between the two once the extender is imported. This makes it particularly useful when attributes are involved, so you don't have to clutter up your struct definition with a bunch of hidden accessor methods. If you did have a static attribute, you can use either an instance extender or a static extender -- either one will work. :=

Crimson Wizard

#4
Quote from: Snarky on Mon 16/10/2017 08:03:52
I didn't know you could use extenders as attribute accessors.

BTW, this also makes it possible to declare "overriding" property accessors for structs that extend parent structs (Or so I remember).

SMF spam blocked by CleanTalk