I'm curious about future prospects on a function call operator in Angelscript. Messy though they can be, operator() overloads are super-useful and something I use frequently in C++ to avoid wordy APIs. It also allows for functors and the like.

As an example, I have a module called "Random" in my game engine, exposed to Angelscript as a global, which can generally be treated like an overloaded function to generate random numbers with various parameters. Additional Random objects can also be created for deterministic simulations and the like, so I'd be losing some functionality if I just exposed this stuff as global functions.

I currently do not have any plans on adding support for function call operators in the script language. Though I won't go so far as saying that it will never be done, I just don't feel they add enough value to make it worth it at the moment.

That doesn't mean you can't register your Random class with AngelScript though. You just have to give a name for your nameless functions when registering them, example:

For my part, it's a feature I'd really like to see, but I've also written a parser or two and know it would be a giant pain in the butt to implement. So I understand if it's late or never. To be honest I'd take property accessors over function-call operators any day of the week.

Pardon the necro-post; the release of version 2.24 makes this relevant again.

A statement from Andreas in my topic on hardcoding geometry and initializer lists:

TheAtom reported a bug today about making calls with function defs. I still need to investigate what changes needs to be made to support those scenarios, but as they look similar in syntax to what the use of a function call operator might look like I recommend you wait a little until I've fixed that bug before you dig too deep into the code.

Since the improved semantics for function pointers are now implemented, how straightforward would the implementation of an opCall be? (Either as a new official addition to the language or, barring that, as a hack to my own copy?)

I believe it ought to be pretty straight forward now. It should only require a few changes to the asCCompiler class. There are basically two places that needs to be updated, CompileFunctionCall() and CompileExpressionPostOp().

The first is for when the expression looks like an ordinary function call, i.e.

There is nothing particular about it. It's just a comment I added for myself to check upon at a later stage.

Let me know if you encounter any difficulties and I'll try to help.

Another tip to make it easier to understand, is to compile a script where the opCall method is called explicitly and then checking the debug output of the bytecode (written to the AS_DEBUG folder). You'll want the bytecode to be identical both when the method is called implicitly and explicitly. Turn off the bytecode optimization when doing this (asEP_OPTIMIZE_BYTECODE) so you'll know what instructions the compiler needs to output before the code goes through the optimization pass.

I got sidetracked from this for about a week. Back into the fray of things.

Question for Andreas: Where in CompileFunctionCall is the "this" value indicated to the bytecode? I'm getting my head around expression contexts et cetera.

EDIT: Partially answered my own question. (at least sort of -- CompileFunctionCall is evidently only used for "get" accessors and function calls that are not part of a larger expression?) I can see now how callable variables (funcPtrs and opCall-able objects) throw a wrench into the compiler's current handling of function calling...

EDIT: I'm going to invest the time to get a better top-down understanding of the compiler's architecture, I think... Still no idea how the 'this' reference is handled.

In case of an implicit this pointer, i.e. when a class method is called from within another method, the CompileFunctionCall() pushes the this pointer onto the stack after it has determined that it is a class method that is being called. You'll find the following code, early in the CompileFunctionCall()

// The object pointer is located at stack position 0
ctx->bc.InstrSHORT(asBC_PSF, 0);
ctx->type.SetVariable(dt, 0, false);
ctx->type.dataType.MakeReference(true);

When it is not an implicit this pointer, then the object pointer is pushed on the stack in CompileVariableAccess() (look for THIS_TOKEN). In this case the compiler will go through the CompileExpressionPostOp where the . operator (if( op == ttDot )) case will invoke the CompileFunctionCall().

Below is my current progress with CompileFunctionCall. It looks like the CompileVariableAccess that looks for a callable variable is already doing the work of pushing the called object onto the stack. It's hilarious to think this might work in some naive way. However, I doubt it does. I'm guessing I need to deal with the format of the variable (reference/dereference it?) and possibly store a temporary copy, as is done for funcdefs toward the bottom.

The supposed necessity of a temporary variable here actually baffles me a little, given the only eligible identifiers are local, class and global variables of funcdef type.

There was indeed a bug, but it turns out that it was different from what I expected. Rather than global variables taking precedence over local class methods incorrectly, the problem is that local class methods take precedence over local variables of the same name.

I'll have to make some changes in CompileFunctionCall() to properly handle this. But don't worry too much about this in your work. It's after all only a problem when the variable happens to have the same name as the class method.

I've fixed this problem in revision 1410. The CompileFunctionCall() has been rearranged to properly handle the visibility of local versus member versus global symbols, and CompileVariableAccess() has a new argument to exclude global variables in searches.