View Issue Details

IDProjectCategoryView StatusLast Update
0000732LDMudLPC Languagepublic2020-04-29 00:14
Reporter_xtian_ Assigned ToGnomi  
PrioritynormalSeverityfeatureReproducibilityN/A
Status resolvedResolutionfixed 
Summary0000732: strict resolved call-others? and a new operator
DescriptionI don't know if this has ever been proposed. Probably.

I have been thinking about an efun that does what call_resolved() does, but with the call_other syntax and throws an error when a call could not be resolved. In brief:

  call_strict( ob, "fun" );

or a more beautiful

  ob=>fun() or ob.fun() or ob==>fun() (suggestions)

throws an error at runtime, if ob has no accessible function "fun".

The reason behind this: In LPC we have no good way to express interface relationships since all our objects are of the same type and call-others at runtime don't need to be resolved. The above is a short-hand for using call_resolved() and checking for an error, but I find it much more expressive and readable and worth being implemented in the language.
TagsNo tags attached.
External Data (URL)

Activities

zesstra

2010-03-04 15:44

administrator   ~0001760

I don't really like => or ==> because they are too easily confused with comparisons.
The dot would be better, but it may clash with the struct lookup, I don't know if the compiler is clever enough (AFAIR there was once the plan to use -> for struct lookup, which did not work for compiler reasons).

_xtian_

2010-03-04 15:56

reporter   ~0001761

Hmm, the dot also suggests some kind of static checking, which wouldn't be the case here ...

Largo

2010-03-04 17:57

reporter   ~0001762

I don't see why the dot suggests static checking more or less than the call_other() operator (->).

Why don't we couple strict function resolving to an (existing) pragma? Since load_object() has been added, the number of unresolved function calls should have been decreased significantly. ;-)

Besides: Why has call_resolved() been designed to return a success value instead of raising an error, too? One could use function_exists() if he wanted to handle non-existent functions.

bubbs

2010-03-05 11:56

reporter   ~0001763

Couldn't you achieve this through a simul_efun to call_other ?

Bardioc

2010-03-05 14:08

reporter   ~0001764

We implemented a Warning system for calls to non-existing functions in EverLIB as follows:

in our master in inaugurate_master():
set_driver_hook(H_DEFAULT_METHOD, "unresolved_method_call");

in our base object that is inherited by ALL other objects. Parts are EverLIB specific, but I think you get the idea. This works GREAT and it helped us to find ALOT of bugs. Its fast enough too!

public status unresolved_method_call(mixed result, string fun, varargs args)
{
    if (object_name(this_object()) + ".c" == __FILE__)
    {
        return FALSE;
    }

    if (member(omitted_methods, fun) || fun == "reset" || fun == "clean_up"
            || (sizeof(fun) > 0 && fun[0] == '-'))
    {
        return FALSE;
    }

    string msg;

    if (previous_object() == NULL)
    {
        msg = sprintf("Non-existing method <%O>::%s() called\n", this_object(), fun);
    }
    else
    {
        msg = sprintf("<%O> called non-existing method <%O>::%s()\n"
                      , previous_object(), this_object(), fun);
    }

    if ( this_player() != NULL
         && interactive(this_player())
         && (status) this_player()->instance_of("/class/interactive/interactive")
         && ( (status) SECURITY->user_id_exists( (string)this_player()->get_normalized_name() )
              || 1 == (int)SE_ACCESS_CONTROL->is_valid_testplayer( this_player() ) ) )
    {
        // send this to the player, but bypass the processing of it
        send_message(({ MCC_WARNING, M_PL_ONLY, "WARNING: ", msg }));
    }
    else
    {
        catch(SE_CHANNEL->send("Wrongness", master(), CHANNEL_CMD_SAY, ({ msg }), NULL));
    }

    debug_message(msg, DMSG_STAMP | DMSG_STDOUT | DMSG_STDERR | DMSG_LOGFILE);

    return FALSE;
}

So actually, we do not need to distinguish, we already have the functionality ;-)

_xtian_

2010-03-10 17:41

reporter   ~0001780

Thanks for the code snippets, but the original intention is not to change the behaviour of call_other but to offer a second way of external function calling ... albeit a stricter one.

In our environment the fact that a not-resolved-call-other results in a legal 0 is used quite a lot and I wouldn't want to change that default. (example: if (ob->query_weapon) // react to a weapon ...)

The stricter call would allow code like this:

if (ob->query_weapon)
  ob==>wield(); // if this weapon has not defined a wield() function
                  // this throws an error/warning. this shouldn't happen


Of course we could add a custom simul-efun that does this, but I prefer putting this in the open.
Also that way we can use a nice operator for it, if we can find a suitable one.

zesstra

2010-03-14 11:17

administrator   ~0001795

Another possibility would be to change the behaviour of call_other based on a pragma in the caller (or callee?)... But that would of course have a greater impact and your last example would require a different approach to detect the weapon (function_exists, symbol_function, ...).

Gnomi

2020-04-29 00:14

manager   ~0002529

Implemented in 3.6.2

Issue History

Date Modified Username Field Change
2010-03-04 15:37 _xtian_ New Issue
2010-03-04 15:44 zesstra Note Added: 0001760
2010-03-04 15:56 _xtian_ Note Added: 0001761
2010-03-04 17:57 Largo Note Added: 0001762
2010-03-05 11:56 bubbs Note Added: 0001763
2010-03-05 14:08 Bardioc Note Added: 0001764
2010-03-10 17:41 _xtian_ Note Added: 0001780
2010-03-14 11:17 zesstra Note Added: 0001795
2020-04-29 00:13 Gnomi Assigned To => Gnomi
2020-04-29 00:13 Gnomi Status new => assigned
2020-04-29 00:14 Gnomi Status assigned => resolved
2020-04-29 00:14 Gnomi Resolution open => fixed
2020-04-29 00:14 Gnomi Note Added: 0002529