Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calling a method from an array of classes causes "this" to be null #1110

Open
mikaib opened this issue May 24, 2024 · 6 comments
Open

Calling a method from an array of classes causes "this" to be null #1110

mikaib opened this issue May 24, 2024 · 6 comments

Comments

@mikaib
Copy link

mikaib commented May 24, 2024

If you have an array of classes and you try and index a non-existent index. It will allow you to call methods just fine. But if said method tries to access a variable of the class it will crash, because this is null (however it can call other methods of itself)

This is very weird behaviour to me, but it might be intentional.

class CoolClass {
    public var num:Int;

    public function new(i:Int) {
        num = i;
    }

    public function hi() {
        trace(this);
        trace(num);
    }
}

class Main {
    static function main() {
        trace('Begin');
        var myCoolClasses:Array<CoolClass> = [];

        myCoolClasses.push(new CoolClass(1));
        myCoolClasses.push(new CoolClass(2));

        // Index 0 and 1 available, lets call indexes 0, 1 and 2
        myCoolClasses[0].hi();
        myCoolClasses[1].hi();
        myCoolClasses[2].hi();
        trace("End");
    }
}

afbeelding

@thomasjwebb
Copy link

I'm not sure what the design philosophy is but it could be that this is the expected behavior and that haxe is designed to defer to the target's typical handling of the situation. I made a minimal example and tried a few targets

class NullTest
{
    public function new() {}

    public function doSomething() {
        trace(this);
    }
}

class Main
{
    public static function main() {
        var arry = new Array<NullTest>();
        arry[0].doSomething();
    }
}

For python I get:
AttributeError: 'NoneType' object has no attribute 'doSomething'

For nodejs I get:
TypeError: Cannot read properties of undefined (reading 'doSomething')

For hxcpp I get:
src/Main.hx:48: null

For hashlink I get a segfault, which is kinda weird:
zsh: segmentation fault hl bin/test.hl
I would expect it to either have hxcpp's behavior or python & js's behavior

hxcpp is basically behaving the way C++ behaves. This example:

#include <iostream>

class A
{
public:
A() {};
void draw() { std::cerr << (size_t)this << std::endl; };
};

int main()
{
A *a = nullptr;
a->draw();
}

Outputs 0.

@thomasjwebb
Copy link

Oh and if I use hashlink's compiled output it's more explicit that it's an uncaught exception so that's more analogous to the behavior in python and js.

Uncaught exception: Null access

@barisyild
Copy link

There is no problem because the Array starts without elements.

var integers:Array<Int> = [];
integers.push(10); // Index 0
integers.push(8); // Index 1

var integer1:Int = integers[0];
var integer2:Int = integers[1];
var integer3:Int = integers[2]; // This value is “null” because we have not written anything to the index 2.
trace(integer1, integer2, integer3); // 10, 8, null

@barisyild
Copy link

barisyild commented Jun 10, 2024

If you have an array of classes and you try and index a non-existent index. It will allow you to call methods just fine. But if said method tries to access a variable of the class it will crash, because this is null (however it can call other methods of itself)

This is very weird behaviour to me, but it might be intentional.

class CoolClass {
    public var num:Int;

    public function new(i:Int) {
        num = i;
    }

    public function hi() {
        trace(this);
        trace(num);
    }
}

class Main {
    static function main() {
        trace('Begin');
        var myCoolClasses:Array<CoolClass> = [];

        myCoolClasses.push(new CoolClass(1));
        myCoolClasses.push(new CoolClass(2));

        // Index 0 and 1 available, lets call indexes 0, 1 and 2
        myCoolClasses[0].hi();
        myCoolClasses[1].hi();
        myCoolClasses[2].hi();
        trace("End");
    }
}

afbeelding

There, problem solved.

Things to keep in mind;
Push function gives index value sequentially.
The i value in the class is just a variable in the class and has no effect on the index.
You can read as many values as you push, if you read more indexes than you push, you will get a null value.

class CoolClass {
    public var num:Int;

    public function new(i:Int) {
        num = i;
    }

    public function hi() {
        trace(this);
        trace(num);
    }
}

class Main {
    static function main() {
        trace('Begin');
        var myCoolClasses:Array<CoolClass> = [];

        myCoolClasses.push(new CoolClass(1)); // Index 0
        myCoolClasses.push(new CoolClass(2)); // Index 1
        myCoolClasses.push(new CoolClass(3)); // Index 2

        myCoolClasses[0].hi();
        myCoolClasses[1].hi();
        myCoolClasses[2].hi();
        trace("End");
    }
}

@thomasjwebb
Copy link

There is no problem because the Array starts without elements.

I think the poster's point is not about arrays but about inconsistent behavior when calling functions on uninitialized objects between targets. The array aspect of this is kind of a red herring. See my first comment where I illustrated the same thing by declaring a variable as an instance of a class but assigning null to it.

@thomasjwebb
Copy link

thomasjwebb commented Jun 10, 2024

Oh I realized I also used arrays to illustrate the issue in my first reply. Forget about arrays. You can illustrate this without any arrays being involved:

class NullTest
{
    public function new() {}

    public function doSomething() {
        trace(this);
    }
}

class Main
{
    public static function main() {
        var n:NullTest = null;
        n.doSomething();
    }
}

exhibits the same behavior. This is just about differences between how targets handle calling methods on null instances of a class potentially causing confusion when debugging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants