Jump to content

  • Log In with Google      Sign In   
  • Create Account

Sir Ementaler

Member Since 09 Mar 2013
Offline Last Active Yesterday, 05:21 PM

Topics I've Started

Conditional operator is unusable with functions.

17 October 2015 - 04:07 AM

Here's something I run into on a regular basis; consider the following code:

funcdef fd@ fd();
fd@ f() {
	return true ? f : f;
}

This will not compile because it "can't implicitly convert from '$func@' to 'fd@'". As far as I can tell, there's in fact no way to use the result of a conditional expression whose result is an unspecified function handle. I attempted conversions and casts but they're unsurprisingly ineffective. I also tried calling a result but that is similarly impossible:

void f() {
	(true ? f : f)();
}

This code fails with "No matching signatures to '$func::opCall()'". To my surprise, the conditional operator also doesn't differentiate between functions with completely varying signatures, i.e. the following code actually compiles:

int g(int) {
	return 0;
}
void f() {
	true ? f : g;
}

Not that the result is possible to use in any way. Another interesting fact is that whereas code

funcdef fd@ fd();
fd@ f() {
	fd@ h = f;
	return true ? h : f;
}

compiles, very similar code

funcdef fd@ fd();
fd@ f() {
	fd@ h = f;
	return true ? f : h;
}

does not. It appears to me that making all of this work as expected would require major changes to the engine, so as a more viable solution I'd suggest enabling the syntax:

funcdef fd@ fd();
fd@ f() {
	return true ? fd(f) : fd(f);
}

i.e. explicit conversion to a specific function handle.


Possible dictionary optimization

28 July 2015 - 11:46 AM

Hi, I was skimming through scriptdictionary.cpp today to see some implementation details, and I couldn't help but notice the quite wordy implementation of CScriptDictionary::operator[]. Let me quote:

CScriptDictValue *CScriptDictionary::operator[](const string &key)
{
	// Return the existing value if it exists, else insert an empty value
	map<string, CScriptDictValue>::iterator it;
	it = dict.find(key);
	if( it == dict.end() )
		it = dict.insert(map<string, CScriptDictValue>::value_type(key, CScriptDictValue())).first;
	
	return &it->second;
}

It came to my attention that this is essentially a lengthy rewording of the following code:

CScriptDictValue *CScriptDictionary::operator[](const string &key)
{
	return &dict[key];
}

(see http://en.cppreference.com/w/cpp/container/map/operator_at or http://www.cplusplus.com/reference/map/map/operator[]/ for reference for std::map operator[]). I wanted to see if something escapes my attention so I tested performance of both of these implementations with the following script:

void test() {
	array<string> keys;
	for (uint i = 0; i < 100000; i++)
		keys.insertLast(formatInt(i, "", 10));

	uint insertionTime = 0, accessTime = 0;
	for (uint i = 0; i < 100; i++) {
		dictionary d;

		uint time1 = GetSystemTime();

		for (uint j = 0; j < 100000; j++)
			d[keys[j]] = j;

		uint time2 = GetSystemTime();

		for (uint j = 0; j < 100000; j++)
			if (uint(d[keys[j]]) != j)
				return 0;

		uint time3 = GetSystemTime();

		insertionTime += time2 - time1;
		accessTime += time3 - time2;
	}
	Print("Insertion time: " + insertionTime + " ms\nAccess time: " + accessTime + " ms\n");
} 

Using AngelScript compiled in MSVC 2013 I obtained the following results:

 

Current implementation:

In Release mode: Insertion time: 18334 ms; Access time: 11434 ms

In Debug mode: Insertion time: 846300 ms; Access time: 300030 ms
 

Proposed implementation:

In Release mode: Insertion time: 15181 ms; Access time: 12121 ms

In Debug mode: Insertion time: 577720 ms; Access time: 271790 ms

 

I.e., in all situations except for Release mode access the simpler implementation was faster. It may be a bit of a tradeoff but looks worth it. I don't know how other compilers would react though. Either way I thought you may be interested.


Errors produced by classes in namespaces accessing global properties

03 March 2015 - 04:08 PM

Using AngelScript 2.30.0, I encountered these two today:

 

An unjustified compile time error when a method of a class in a namespace calls a function with an argument that defaults to a global variable:

int i;
void f(int a = i) {}
namespace n {
 class c {
  void m() {
   f();
  }
 }
}
script.as (5, 3) : INFO : Compiling void c::m()
default arg (1, 1) : ERR : 'i' is not declared
script.as (6, 4) : ERR : Failed while compiling default arg for parameter 0 in function 'void f(int = i)' 

An unjustified compile time error when a class in a namespace has a property that defaults to a global variable:

int i;
namespace n {
 class c {
  int p = i;
 }
}
script.as (3, 8) : INFO : Compiling c::c()
script.as (4, 11) : ERR : 'i' is not declared

The errors disappear if "::" is added in front of "i" in the appropriate places in the above examples but given the conditions it shouldn't be required (and, in the former case, may be impossible to add from script level if the function in question is registered by the application).


Error for non-default namespace interfaces used in methods of mixin classes inherited f...

21 January 2015 - 03:06 PM

I just couldn't help but make the title comprehensive.

Here's an example piece of code that, tested in AngelScript 2.29.2, causes a compilation error that shouldn't happen:

namespace n {
	interface i {}
	mixin class m {
		void f(i@) {}
	}
}
class c : n::m {}

The error reads:

ERR : Identifier 'i' is not a data type in global namespace

...which is irrefutably true, but hardly justifying. Handles to the interface can be used correctly as members of the mixin class but an attempt to use them as method arguments or other local variables in methods will make the compiler try to use types defined in the global namespace (or whatever the namespace of the class named "c" in the example is). It goes without saying that this may have bad consequences if, for example, both the local and global namespaces contain an interface named "i" and the mixin class is registered as:

mixin class m {
	i@ foo;
	void f(i@ bar) {
		@foo = @bar;
	}
}

Such code will generate a rather hilarious error:

ERR : Can't implicitly convert from 'i@&' to 'i@'.


opCall access violation

21 July 2014 - 08:59 AM

The following script in 2.29.1 and earlier versions:

class foo {
  void opCall(string) {}
}
void main() {
  array<foo> bar(1);
  bar[0]("");
}

causes an access violation on attempt to execute. As far as I can tell, the conditions are rather specific and it's required that opCall has at least one string or string reference (or another similar object) argument and it's also necessary for opCall to be called on an array element (or perhaps another reference) rather than a freestanding instance. If the call to opCall is made explicit, i.e. 

bar[0].opCall("");

the error will not occur either.

 


PARTNERS