Advertisement

[EXPERIMENTAL PATCHES] Named arguments and auto declarations.

Started by January 22, 2014 05:06 AM
14 comments, last by WitchLord 10 years, 7 months ago

Hi! I've created two experimental new language features for angelscript because I felt certain things were more annoying to do than they should have been. They have been manually tested for a bit, and I have included new tests in the angelscript test suite for them, but they're still relatively new code that hasn't gone through rigorous use.

I have no idea whether these are actually language features you want, Andreas, so if you have any remarks on their concept or implementation I would love to get some feedback. That goes for all you other angelscript users as well, feel free to try them out and suggest changes.

Both patches should work on r1813.

Named Arguments

Motivation

I had a function declared:


string getTooltip(bool showNames = true, bool showSize = true, bool showCost = true);

and I was getting annoyed at having to type:


getTooltip(true, true, false);

so I implemented named arguments so you can do the more readable:


getTooltip(showCost=false);

Implementation

The parser creates a new type of node when the structure for a named argument is detected in an argument list, the compiler sees this node type and uses modifications to the functions CompileArgumentList, CompileDefaultAndNamedArgs (previously CompileDefaultArgs) and MatchFunctions to put the arguments in the right spots and fill in the defaults.

Compatibility

The syntax for default arguments conflicts with a previously possible syntax of using the value of an assignment as an argument, ie


int x = 4;
func(a, x = 8);
//we want x to be 8 now.

in my experience, this syntax is used very rarely and is quite ugly. If you think this will be a problem, I could add an engine option to disable the named argument syntax for backwards compatibility.

The same behaviour will still be possible by doing:


func(a, (x = 8));

Auto Declarations

Motivation

I noticed myself writing a lot of code akin to:


const PlanetDesignationType@ type = getPlanetDesignationType(id);

In C++, I would normally use C++11's auto keyword to remove the duplication there, since the type is already obvious from the right hand side of the assignment. I implemented a very limited version of C++'s auto keyword for use just in local and global variable declarations to simplify it to this:


auto type = getPlanetDesignationType(id);

Implementation

This one was a bit trickier, since it involved changing the order of how certain things happened to compile the value for the variable first. I ended up creating a helper function in the compiler, CompileAutoType, that compiles an expression from a node and overrides a datatype to the resolved type. The now compiled expression is then passed forward to the initialization step for use.

Global variables had some additional issues, since their compilation only happened later on. I:

1. Reordered CompileGlobalVariables() in asCBuilder::Build() to go before everything else, so classes and functions can reliably access the globals with their real type.

2. Global variable registration does not allocate the property right away, but leaves sGlobalVariableDescription.property null until the variable gets a chance to be compiled and resolved.

I've tested everything with these changes and it doesn't seem to cause any problems, but tell me if either of those violates some assumption that I've missed.

Auto does not work in class member declarations, since those are compiled as part of the constructor function and can access constructor arguments, leading to potential ambiguities with multiple constructors.

Compatibility

Anything using 'auto' as an identifier will not be compatible with this change, sadly. I could add an engine option to disable autos for backwards compatibility if you think it's necessary.

These look like interesting additions, especially the auto keyword.

Advertisement

Looks very awesome!!!

I like the 'named arguments' feature. It is something that I feel is missing from the C++ language too. The example you gave is perfect and I often get annoyed at the very same thing in C++.

I'm not too fond of 'auto declarations' though. I don't use them in C++, except in occassional template declarations where the type isn't known before hand. Still, I won't let my personal opinion prevent the enhancement of the library.

I thank you for these patches and I'll be sure to evaluate them as soon as possible for inclusion into the SVN.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game


getTooltip(showCost=false);

Can you only use named params for params which have default values, or for any function?


void foo(int x, float y)
{ ... }

// would this work?
foo(y = 123.45f, x = 789);

Yes, you can use named arguments for parameters without default values as long as you make sure every required parameter has a value.

Advertisement

Great additions indeed. Good job, GGLucas! Although I have a question how 'auto' is going to resolve the ambiguity between, say, const @ and non-cost @ when the right part returns a non-const @? Quite often you'd want a const @ in the left part..

If the right hand side is non-const then the auto will resolve to non-const by default, except if you write it as:


const auto varname = getNonConstHandle();

Great!

Another potential use for 'auto' would be loop iterators but it looks like a somewhat more complex case to me, since compiler would need to consider both the initial assignment of the auto var and the loop condition. For example:


uint maxPlayers = 100;
for( auto i = 0; i < maxPlayers; i++ ) {

and


uint maxPlayers = 100;
for( auto i = 0; i < maxPlayers-1; i++ ) {

In the first case auto should be interpreted as an unsigned int, but as a signed int in the second.

Just tested with your patch applied and in the first case the auto iterator is interpreted as a signed int, resulting in compilation warning due to signed/unsigned comparison in loop condition.

Although on another though, some kind of builtlin range type to iterate upon would be even better for the purpose. No need for the compiler to hack into the loop condition then to figure out the 'auto' iterator.

This topic is closed to new replies.

Advertisement