static member initialized to null compiles to undefined on JavaScript target #5897

Open
binki opened this Issue Dec 20, 2016 · 5 comments

Projects

None yet

3 participants

@binki
Contributor
binki commented Dec 20, 2016

This might be like #3877.

In this http://try.haxe.org/#A9e66

import haxe.Json;

class Test {
    static var nullStaticMember = null;

    static function main() {
        var x = {z: {}};
        trace(Json.stringify(x));
        x.z = null;
        trace(Json.stringify(x));
        x.z = nullStaticMember;
        trace(Json.stringify(x));
        
        // Exceptional?
        trace(Json.parse(Json.stringify(null)));
        trace(Json.parse(Json.stringify(nullStaticMember)));
    }
}

the nullStaticMember compiles to undefined instead of null when targeting JavaScript. Inside of most of Haxe, Haxe doesn’t distinguish between undefined and null. However, JSON does distinguish these. I think in this case null should compile to null instead of undefined (actually, it’s omitting the initialization for nullStaticMember altogether). I.e., the following statements should be equivalent:

x.z = null; // Assign null directly, compiled to null
x.z = nullStaticMember; // Assign a class variable of the same type initialized to null, compiled (wrongly?) to undefined

It is unintuitive that those statements behave differently. This matters more when using a format such as JSON which is often an interchange format. It is conceivable that services which validate JSON might even require you to provide a key explicitly set to null instead of omitting the key. Or if you expect to be able to pass the results of Json.stringify() to Json.parse() you’ll find that null can be round-tripped while undefined cannot. JavaScript runtimes even throw a SyntaxError if you try to parse the result of stringifying undefined.

I see this in both haxe-3.3 (try website) and haxe-3.4rc1/3.4.0 (local CLI).

@binki binki changed the title from null compiles to undefined on JavaScript target to static member initialized to null compiles to undefined on JavaScript target Dec 20, 2016
@Simn
Member
Simn commented Dec 20, 2016

genjs indeed skips the assignment when the expression is null. Does anyone remember why it does that?

@binki
Contributor
binki commented Dec 23, 2016

If this issue is considered valid, how is #5905 invalid? They’re both instances of Haxe exposing developers to JavaScript’s undefined value but through different means. This bug is about an = null being omitted resulting in variable access returning undefined instead of null in user-authored code. The other is about the Haxe std-provided Map.get() implementation returning undefined when the API documentation declares it would return null. They would need different test cases ;-).

@Simn
Member
Simn commented Dec 23, 2016

I'm mostly curious why we skip null assignments on JavaScript.

@RealyUniqueName
Member

My quess it was some sort of optimization: why spend time assigning null if undefined and null are the same for haxe?

@binki
Contributor
binki commented Dec 23, 2016

But if null and undefined are really the same for haxe, shouldn’t its Json.stringify() behavior reflect that? Depending on where I get null from, it outputs something different—even though haxe has compile-time type information that says that my object should have a key, it is omitted from JSON if I get a runtime undefined:

http://try.haxe.org/#8c488

import haxe.Json;

class Test {
    static var uninitializedVar:String = null;
    
    static function main() {
        var x:{id:String,} = {
            id: null,
        };
        trace(Json.stringify(x)); // {"id":null}

        x = {
            id: ['a' => 'b',].get('c'),
        };
        trace(Json.stringify(x)); // {}
                 
        x = {
            id: uninitializedVar,
        };
        trace(Json.stringify(x)); // {}
    }
}

In my observations so far, undefined and null behave differently, even in specified situations (though right now the only specified situation I can think of is Json.stringify()).

@Simn Simn modified the milestone: 4.0 Jan 9, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment