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

[analyzer] type guards #5167

Closed
nadako opened this issue Apr 26, 2016 · 7 comments
Closed

[analyzer] type guards #5167

nadako opened this issue Apr 26, 2016 · 7 comments

Comments

@nadako
Copy link
Member

nadako commented Apr 26, 2016

Something from TypeScript to consider:

function foo(x:Dynamic) {
    if ((x is String)) {
        $type(x); // String
        $type(x.length); // Int
    }
}

See TS Spec: https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#4.24. That alone could help writing code that is both more concise and performant (on static targets, at least).

However, TS has another nice related feature: user-defined type guards. I.e.:

function isCat(a: Animal): a is Cat {
  return a.name === 'kitty';
}

var x: Animal;
if(isCat(x)) {
  x.meow(); // OK, x is Cat in this block
}

That would help a lot when working with anonymous structures where reflection is required to determine the actual value type. I think this also plays well with our Std.is, Reflect.isFunction, etc functions. e.g.:

function foo(a:Animal) {
    if (Std.is(a, Cat)) {
         $type(a); // Cat
    }
}
@Simn
Copy link
Member

Simn commented Apr 26, 2016

From my experience with GADT this is not gonna be very easy to support in our type system. I don't understand the second example though, how is that different from a constrained type parameter? In fact, how is it different from declaring the function isCat(a: Cat)?

@nadako
Copy link
Member Author

nadako commented Apr 26, 2016

The second example is about downcasting, here's what I have in mind regarding structure types:

typedef MapItem = {
    type:String,
}

typedef House = {
    >MapItem,
    numRooms:Int,
}

class Main {
    static function isHouse(mapItem:MapItem):(mapItem is House) {
        return mapItem.type == "house";
    }

    static function doMapItemStuff(mapItem:MapItem) {
        if (isHouse(mapItem)) {
            $type(mapItem); // House, because isHouse returned true and its return value defined as `(argName is Type)`
        }
    }
}

@Simn
Copy link
Member

Simn commented Apr 26, 2016

That reminds me of Rust's typestate: http://pcwalton.github.io/blog/2012/12/26/typestate-is-dead/

@ousado
Copy link
Contributor

ousado commented May 8, 2016

Regarding user defined type guards, I think it's possible to implement them already, using GADTs, like here:
https://gist.github.com/ousado/9e38931c1380025ba459
Regarding built-in type guards, I think that would boil down to another equally limited version of Std.is with equally abysmal performance.

@nadako nadako added this to the Long term milestone May 21, 2016
@Simn Simn modified the milestones: Long term, Design Apr 17, 2018
@Simn
Copy link
Member

Simn commented Sep 3, 2018

It occurred to me that this would be a breaking change in this contrived example:

function foo(x:Dynamic) {
	if ((x is String)) {
		$type(x); // String
		x = 1; // Int should be String
	}
}

@nadako
Copy link
Member Author

nadako commented Sep 3, 2018

IIRC, TS remembers the wider type for assignment

@Simn
Copy link
Member

Simn commented Jun 5, 2020

This would have to go through a haxe-evolution with actual design and shit.

@Simn Simn closed this as completed Jun 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants