Loss of scope in functions returned by _get metamethod

Hi guys,

I seem to be losing sight of my root table when I return a function via the _get metamethod. I can resolve global items only by prepending with ‘::’, which I’d rather avoid. Is there another way to do this / is it a bug? Example Below:

class Moo
{
    _targetPower_kW = 0;
    
    function setTargetPower_kW( targetPower_kW )
    {
        ::server.log("Moo " + targetPower_kW + " Moo " + _targetPower_kW);
        _targetPower_kW = targetPower_kW;
    }
    
    function _get( key )
    {
        if( key == "setTargetPower_kW" )
        {
            return @(targetPower_kW)(setTargetPower_kW(targetPower_kW)).bindenv(this);
        }
    }
    
}

moo <- Moo();

moo.setTargetPower_kW( 10 );
server.log("MooMoo :" + moo._targetPower_kW);

Many thanks

Hi, can you give some more detail on what you trying to achieve?

If I run the above code it outputs MooMoo :10 as I would expect.

I don’t understand the _get part though, a _get metamethod is called when a table entry doesn’t exist (classes are only sorta tables with functions for slots). but setTargetPower_kW does exist so the _get is never invoked.

perhaps you meant this? Although I’m not sure what the use case for something like this would be?

class Moo
{
    _targetPower_kW = 0;
    
    function setTargetPower_kW( targetPower_kW )
    {
        ::server.log("Moo " + targetPower_kW + " Moo " + _targetPower_kW);
        _targetPower_kW = targetPower_kW;
    }
    
    function _get( key )
    {
        if( key == "setTargetPowerV2_kW" )
        {
            ::server.log("I'm in the _get");
            return setTargetPower_kW;
        }
    }
    
}

moo <- Moo();
moo.setTargetPowerV2_kW( 10 );
server.log("MooMoo :" + moo._targetPower_kW);

Sorry, bad example, I didn’t mean to use the same name in the function but the issue is the same and has perhaps got me closer to the problem.

Just by the very presence of having ‘function _get( key ) {}’ in a class, functions seem to lose access to their root tables:

class Moo
{
    _targetPower_kW = 0;
    
    function setTargetPower_kW( targetPower_kW )
    {
        server.log("Moo " + targetPower_kW + " Moo " + _targetPower_kW);
        _targetPower_kW = targetPower_kW;
    }
    
    function _get( key ) {}
}

moo <- Moo();

moo.setTargetPower_kW( 10 );
server.log("MooMoo :" + moo._targetPower_kW);

Results in:
|2019-07-03T17:18:21.128 +00:00|[Agent]|ERROR: the index ‘log’ does not exist|
| — | — | — |
|2019-07-03T17:18:21.128 +00:00|[Agent]|ERROR: in setTargetPower_kW agent_code:7|

Ultimately I’m using _get() as a way to implement dynamic functions / interfaces.

server.log is a global function. So you have to use :: within a class (or any other non-root scope). There is nothing wrong with using :: in fact I personally think it’s preferable to use it everywhere, even within root as it makes it clear you are using a global function.

Rich

I don’t believe that’s the case but I do seem to have resolved my own issue, I wasn’t always throwing null by default within the _get metamethod, that seems to have cleared up the odd behaviour.

Yes, sorry “have to” was a bit strong, “preferable” would have been better as the times it will fail can be a bit subtle like this. Always appending :: would make it less brittle.

So, as you probably worked out, what is happening is it’s attempting to find “server” in Moo’s table of functions, the _get is not handling it “cleanly” (throw null indicates “cleanly” ignoring a _get) and because of this it breaks the fallback to using the functions in the root scope and just says it doesn’t exist. If you add the following you can see it in action:

function _get( key ) { ::server.log("getting: " + key)}

Rich