Using an array as a parameter in Haxe - haxe

I have a function that takes an array as a parameter, and it keeps returning the following error message:
Test.hx:34: characters 23-24 : Array<Int> should be { length : Void -> Int }
Test.hx:34: characters 23-24 : Invalid type for field length :
Test.hx:34: characters 23-24 : Int should be Void -> Int
Test.hx:34: characters 23-24 : For function argument 'array'
This is the code that produced the error message:
class Test{
static function main() {
var a = new Array();
a = [1,2,3,4];
enlarge1DArray(a); //why won't it work when I try to invoke this function?
}
static function enlarge1DArray(array){
var i = 0;
while(i < array.length()){
i++;
trace("i is " + i);
}
}
}

The length you are trying to access is a property, not a method. See the Array API Documentation.
Change the while line from this:
while(i < array.length())
to this:
while(i < array.length)
Detailed Answer:
The error you're getting is due to Haxe getting confused as it's guessing at the types. Basically, because you had were treating length as a method, it was assuming that the array parameter in the enlarge1DArray had to be some kind of object that had a method called length, with the type signature "Void->Int".
In short, because you were asking for a method, it was expecting the parameter "array" to have:
{ length : Void -> Int }
when an Array actually has:
{ length : Int }
So the compiler got confused and said you had your typing wrong. You can read more about this on the Haxe wiki page for Type Inference. In future you can explicitly state what the types of each function parameter are, and then Haxe will give you more useful error messages.

Related

std::list<int> predicate call to function: Error C3867 function call missing argument list

I am using std::list's predicate to update the list based on predicate. But calling in the OnInitDialog() throws compilation error. My code is as follows:
The below is .h:
class CDlgWindow : public CDialog
{
private:
bool single_digit (const int &value);
int _days;
}
The below is .cpp:
CDlgWindow::CDlgWindow(CWnd* pParent, CString strInfo, int days) //ctor
{
_days = days;
//_strInfo = strInfo
}
bool CDlgWindow::single_digit(const int& value)
{
return (value >= _days);
}
BOOL CDlgWindow::OnInitDialog()
{
CDialog::OnInitDialog();
CenterWindow();
.
.
.
int numArr[] = {10,20,30,40};
int size = sizeof(numArr)/sizeof(numArr[0]);
std::list<int> numList (numArr, numArr+size);
numList.remove_if(single_digit); //Error C3867 here!
.
.
}
Complete error message:
Error C3867 function call missing argument list, use '&CDlgWindow::single_digit' to create a pointer to member.
I am trying to understand the functors concept. As I checked in C++11, we have lambdas for easier implementation. Please guide me to understand more on this issue. Thanks!
std::list's remove_if member needs a unary predicate (p) that operates on values (v). The expression p(v) must be valid. Which it isn't if p is a non-static class member (see repro).
There are two options:
Make the predicate (single_digit) a static class member:
class CDlgWindow : public CDialog
{
private:
static bool single_digit (const int &value);
// ...
}
Make the predicate a free function:
bool single_digit(int const& value) {
static int days_ = ...;
return (value >= days_);
}
If you go with option 1 you will have to make _days static as well, since a static member function cannot access non-static instance data. If _days is a compile-time constant, make sure to mark it const as well. That'll open up some compiler optimizations.
This is all hoping that things haven't significantly changed between C++98 and C++11. It's hard to find a C++98 compiler to verify this.

Is it possible in Mono.Cecil to determine the actual type of an object on which a method is called?

For example, consider the following C# code:
interface IBase { void f(int); }
interface IDerived : IBase { /* inherits f from IBase */ }
...
void SomeFunction()
{
IDerived o = ...;
o.f(5);
}
I know how to get a MethodDefinition object corresponding to SomeFunction.
I can then loop through MethodDefinition.Instructions:
var methodDef = GetMethodDefinitionOfSomeFunction();
foreach (var instruction in methodDef.Body.Instructions)
{
switch (instruction.Operand)
{
case MethodReference mr:
...
break;
}
yield return memberRef;
}
And this way I can find out that the method SomeFunction calls the function IBase.f
Now I would like to know the declared type of the object on which the function f is called, i.e. the declared type of o.
Inspecting mr.DeclaringType does not help, because it returns IBase.
This is what I have so far:
TypeReference typeRef = null;
if (instruction.OpCode == OpCodes.Callvirt)
{
// Identify the type of the object on which the call is being made.
var objInstruction = instruction;
if (instruction.Previous.OpCode == OpCodes.Tail)
{
objInstruction = instruction.Previous;
}
for (int i = mr.Parameters.Count; i >= 0; --i)
{
objInstruction = objInstruction.Previous;
}
if (objInstruction.OpCode == OpCodes.Ldloc_0 ||
objInstruction.OpCode == OpCodes.Ldloc_1 ||
objInstruction.OpCode == OpCodes.Ldloc_2 ||
objInstruction.OpCode == OpCodes.Ldloc_3)
{
var localIndex = objInstruction.OpCode.Op2 - OpCodes.Ldloc_0.Op2;
typeRef = locals[localIndex].VariableType;
}
else
{
switch (objInstruction.Operand)
{
case FieldDefinition fd:
typeRef = fd.DeclaringType;
break;
case VariableDefinition vd:
typeRef = vd.VariableType;
break;
}
}
}
where locals is methodDef.Body.Variables
But this is, of course, not enough, because the arguments to a function can be calls to other functions, like in f(g("hello")). It looks like the case above where I inspect previous instructions must repeat the actions of the virtual machine when it actually executes the code. I do not execute it, of course, but I need to recognize function calls and replace them and their arguments with their respective returns (even if placeholders). It looks like a major pain.
Is there a simpler way? Maybe there is something built-in already?
I am not aware of an easy way to achieve this.
The "easiest" way I can think of is to walk the stack and find where the reference used as the target of the call is pushed.
Basically, starting from the call instruction go back one instruction at a time taking into account how each one affects the stack; this way you can find the exact instruction that pushes the reference used as the target of the call (a long time ago I wrote something like that; you can use the code at https://github.com/lytico/db4o/blob/master/db4o.net/Db4oTool/Db4oTool/Core/StackAnalyzer.cs as inspiration).
You'll need also to consider scenarios in which the pushed reference is produced through a method/property; for example, SomeFunction().f(5). In this case you may need to evaluate that method to find out the actual type returned.
Keep in mind that you'll need to handle a lot of different cases; for example, imagine the code bellow:
class Utils
{
public static T Instantiate<T>() where T : new() => new T();
}
class SomeType
{
public void F(int i) {}
}
class Usage
{
static void Main()
{
var o = Utils.Instantiate<SomeType>();
o.F(1);
}
}
while walking the stack you'll find that o is the target of the method call; then you'll evaluate Instantiate<T>() method and will find that it returns new T() and knowing that T is SomeType in this case, that is the type you're looking for.
So the answer of Vagaus helped me come up with a working implementation.
I published it on github - https://github.com/MarkKharitonov/MonoCecilExtensions
Included many unit tests, but I am sure I missed some cases.

Error: TSortedMap with a custom struct as key, overloading operator<

I am trying to implement a TSortedMap with my custom struct as the key. I have overloaded the operators for the struct. However, when I try to compile I get this error at the line of code where I am adding an element to the TSortedMap:
error C2678: binary '<': no operator found which takes a left-hand operand of type 'const T'
(or there is no acceptable conversion)
My struct:
USTRUCT(BlueprintType)
struct FUtility
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite, EditAnywhere, meta=(ClampMin = "0.0", ClampMax = "1.0"))
float value = 0.0f;
UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (ClampMin = "0.0", ClampMax = "1.0"))
float weight = 1.0f;
FORCEINLINE bool operator== (const FUtility& other)
{
return this->value == other.value && this->weight == other.weight;
}
FORCEINLINE bool operator< (const FUtility& other)
{
return (this->value * this->weight) < (other.value * other.weight);
}
.....
friend uint32 GetTypeHash(const FUtility& other)
{
return GetTypeHash(other.value) + GetTypeHash(other.weight);
}
};
Not quite sure why it is not compiling since it is overloaded. Maybe it isn't overloaded correctly. Any help would be greatly appreciated.
Well, oddly enough I figured it out. It was really bugging me that all of the operator logic in the documentation took two parameters. It turns out I was just missing the friend keyword. From there I was able to add the second parameter and it compiled nicely.
Example:
friend bool operator< (const FUtility& a, const FUtility& b)
{
return (a.value * a.weight) < (b.value * b.weight);
}

stringstream peek() error C3867

I have method of a class, that accepts a key variable and looks up the key in an underdone map. The Value is a string example: "12132, jack_arog, 1990:12:8:3:25:3"; method will use peek() in stringstream to recognize ',' and ' ' to ignore them and put the rest in a vector. Afterwards method will assign members of vector to attributes of an object.
Error is recieve during compilation:
if (ss.peek() == ',' || ss.peek == ' ')
ss.ignore();
Error C3867 'std::basic_istream<char,std::char_traits<char>>::peek': non-standard syntax; use '&' to create a pointer to member
I looked up this error and most say you forgot () when calling a function, however i do not believe this is my problem.
Method:
void Account::find_account(std::string name, std::string ID)
{
std::string key = name + "," + ID;
Account new_account;
std::unordered_map<std::string, std::string>::const_iterator got = map.find(key);
if (got == map.end())
std::cout << "not found";
else
{
std::string my_string = got->second;
std::vector<std::string> holder;
std::stringstream ss(my_string);
std::string i;
while (!my_string.empty() && ss >> i)
{
holder.push_back(i);
if (ss.peek() == ',' || ss.peek == ' ')
ss.ignore();
}
for (int i = 0; i < holder.size(); i++)
{
if (i = 0)
new_account.ID = holder.at(i);
if (i = 1)
new_account.account_holder = holder.at(i);
if (i = 2)
{
std::string::size_type sz;
new_account.amount_available = std::stof(holder.at(i), &sz);
}
if (i = 3)
{
new_account.date_created = holder.at(i);
}
}
}
}
"I looked up this error and most say you forgot () when calling a function, however i do not believe this is my problem."
How can you say that when your compiler tells you that the error is exactly on this line? Moreover it is telling you that the error is specifically tied to your (ab)use of peek, I quote:
"...peek': non-standard syntax; use '&' to create a pointer to member
I translate: The compiler thinks you are not trying to call peek, since you did not type the required () to do so. So, if you are by any chance trying to get the function address, you should prepend & to the function name for the syntax to be correct.
Computers are dumb, I'll give you that, but they are rarely wrong.

haxe "should be int" error

Haxe seems to assume that certain things must be Int. In the following function,
class Main {
static function main() {
function mult_s<T,A>(s:T,x:A):A { return cast s*x; }
var bb = mult_s(1.1,2.2);
}
}
I got (with Haxe 3.01):
Main.hx:xx: characters 48-49 : mult_s.T should be Int
Main.hx:xx: characters 50-51 : mult_s.A should be Int
Can anyone please explain why T and A should be Int instead of Float?
A more puzzling example is this:
class Main {
public static function min<T:(Int,Float)>(t:T, t2:T):T { return t < t2 ? t : t2; }
static function main() {
var a = min(1.1,2.2); //compile error
var b = min(1,2); //ok
}
}
I can't see why t<t2 implies that either t or t2 is Int. But Haxe seems prefer Int: min is fine if called with Int's but fails if called with Float's. Is this reasonable?
Thanks,
min<T:(Int,Float)> means T should be both Int and Float. See the constraints section of Haxe Manual.
Given Int can be converted to Float implicitly, you can safely remove the constraint of Int. i.e. the following will works:
http://try.haxe.org/#420bC
class Test {
public static function min<T:Float>(t:T, t2:T):T { return t < t2 ? t : t2; }
static function main() {
var a = min(1.1,2.2); //ok
$type(a); //Float
trace(a); //1.1
var b = min(1,2); //ok
$type(b); //Int
trace(b); //1
}
}

Resources