jsx / JSX

JSX - a faster, safer, easier JavaScript
http://jsx.github.io/
MIT License
1.46k stars 102 forks source link

Map.<varinat> doesn't match with Map.<number> or some specific map isntance. #261

Closed shibukawa closed 10 years ago

shibukawa commented 11 years ago

I wrote following code:

class _Main
{
    static function test(option : Map.<variant>) : void
    {
        for (var key in option)
        {
            log key;
        }
    }

    static function main(argv : string[]) : void
    {
        _Main.test({'key1': 1, 'key2': 2});
    }
}

Map. doesn't match with Map. or some specific map isntance:

$ jsx --run test.jsx
[test.jsx:13:18] no function with matching arguments
        _Main.test({'key1': 1, 'key2': 2});
                  ^

[test.jsx:3:11] Note: candidate function not viable: no known conversion from Map.<number> to Map.<variant> for 1st argument.
    static function test(option : Map.<variant>) : void
           ^^^^^^^^

Following code passes:

_Main.test({'key1': 1, 'key2': 'string'});

I think, it is too strict.

kazuho commented 11 years ago

:+1:

nyuichi commented 11 years ago

No, it must not be allowed. Once the widening introduced that parameter types variation propagates to the parent types (i.e. type covariant) it breaks type safety in the code, like

class _Main {
    static function addStringToMapVariant (variants : Map.<variant>) : void {
        variants['foo'] = 'foo';
    }
    static function main (args : string[]) : void {
        var numbers = {'1' : 1, '2' : 2}; // Map.<number>

        _Main.addStringToMapVariant(numbers);

        log numbers['foo']; // Every member in `numbers` must be a number in this block context but a string returns here
    }
}

OTOH I will agree if constant argument goes to the lang spec, with which we can safely write type covariant Maps as well as Arrays.

class _Main {
    static function takeMapVariant (const variants : Map.<variant>) : void {
        // no destructuring operation against variants is expected to happen in this method
    }
    static function main (args : string[]) : void {
        var numbers = {'1' : 1, '2' : 2}; // Map.<number>

        _Main.takeMapVariant(numbers);
    }
}
nyuichi commented 11 years ago

One more thing: I'm very fine with letting JSX have a special treatment for raw literals passed at the place of argument. In your posting example the passed object of Map.<number> type is an immediate value, i.e. is guaranteed not to be used in any of the contexts existing there, so we can do it special coercion (or possible to say inference if you want) from Map.<number> to Map.<variant> against such values. This is also the case to Array literals.