COMMUNITY

Using local var inside its initialization

Hej all !

I know it’s not possible now but couldn’t we do something with that in the future ?
I mean I often have to write something like that :

var foo = null;
foo = MyClass.init( foo.bar );

Instead of just writing : var foo = MyClass.init( foo.bar ).
Something could maybe be done in internal to make it working ?

Its already possible, using the comma operator :wink:

var foo, foo = MyClass.init( foo );

However, I’m not sure where bar comes from.

Edit: After second thought, this is confusing advice. foo is null at the point you pass it in. If the question is how to use foo directly while assigning it, this might be an option (but maybe better is to just use your initial setup). It won’t work with var foo, foo = MyClass.init( foo.bar ); in this because it will won’t be able to know where foo.bar comes from, both foo and bar are null, since they arent defined. In C# you can pass variables in, which can be altered/assigned within a function and passed back, but Haxe doesn’t have such functionality.

1 Like

Waw !
I didn’t know about that, thanks you Mark !

Bar is inside MyClass instance.
…And also there are good beers inside :smiley:

But why?
var foo = MyClass.init( foo.bar ) would always produce a null pointer exception on foo.bar :slight_smile:

My example is not complete since foo.bar targets something that is called in the future.
I don’t know if it’s clear enough…

Mark’s “solution” actually declares a new variable. So, the second foo and foo.bar reference two different variables.

In my example it is also seen as 2 different variables by the compiler.
But since the bar is called inside a callback, it then should do the link.
I’ll test and tell you then but, is Mark’s solution do exactly the same thing that my example, so it should be ok.

This may be a better example:

var foo = function() foo();

vs

var foo = null;
foo = function() foo();

You can just write function foo() foo().

Level 2:

class Test {
    static function main() {
        var foo = null;
        foo = new Foo(function() foo.f());
    }
}

class Foo {
    public var f:Void->Void;
        
    public function new(f) {
        this.f = f;
    }
}

The main issue here is that you cannot reference the currently declared variable in the init expr. I am not sure if that should be supported though.

I’m sure it should not :slight_smile:

Yes as Kevin said it’s about that. When playing with references it’s useful.
Why exactly it shouldn’t be done please ?
What is the difference when declaring it first as null and then initializing it ?

And yes, the Mark’s solution doesn’t work :confused:
So we are condamned to write that ?

var foo = null;
foo = MyClass.init( foo.bar );

I would question the design of an API that involves passing the object into its own constructor :slight_smile:

As said, it’s not the object itself that I pass but a reference in it that is used later, what’s the matter with that ?
I find more stupid writing somthing like in my example than the design…
And again, just to learn, to understand, I wanted to know what is the problem, the impact of something like var foo = new MyClass( foo.bar ) ?

As said, it’s not the object itself that I pass but a reference in it that is used later

The object doesn’t exist yet, nor does that reference.

Step by step, if you do something like:

var foo = null;
foo = new MyClass(foo.bar);

The sequence of actions taken is:

  1. initialise foo to null
  2. get the value of foo.bar (null pointer exception!)
  3. call the constructor of MyClass with the value foo.bar
  4. set foo to the result of the previous call

There is no clean way to make this API work. What exactly do you want to accomplish @filt3rek?

A possible workaround would be something like:

var foo = null;
foo = new MyClass(() -> foo.bar);

Which avoids the immediate NPE and instead gives the object a function that it can call AFTER the constructor has finished.

Or finally:

var foo = null;
foo = new MyClass(obj -> obj.bar);

Might seem strange but if MyClass needs to “dynamically” get one of its fields, even in the constructor, that could work.

class MyClass {
  var bar:Int;
  var baz:Int;
  public function new(getProp:MyClass->Int) {
    bar = 1;
    baz = 2;
    trace("caller wanted to use field", getProp(this));
  }
}

But again, please, please don’t do this. It is bad API design and there are probably much nicer ways to do what you want.

1 Like

Thanks Aurel for your explanation.

I’ll paste my original code so you could see what I mean because I think my simple example isn’t good :

var questionsListing	: Listing<Question>	= null;
questionsListing	= new Listing(  
[
	...
	ELMove( _->questionsListing.lastReq.ord == "ord" ),
	...
]);

And then in a callback I call the function inside ELMove, so it all exists and run well now.
It’s just about this stupid var questionsListing : Listing<Question> = null;

You have to separate the variable declaration and initialization in cases like these, a very small inconvenience in my opinion.

Also, haxe allows shadowing variables. Consider the case:

var a = 10;
var a = a + 1;
trace(a); // prints 11

This might help illustrate why the variable you are declaring is not yet defined in its own initialization expression. (Though even if shadowing variables wasn’t allowed, it should still behave like this in my opinion)