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

Typed Functions with signatures #207

Open
Harbs opened this issue Jan 18, 2022 · 12 comments
Open

Typed Functions with signatures #207

Harbs opened this issue Jan 18, 2022 · 12 comments

Comments

@Harbs
Copy link
Contributor

Harbs commented Jan 18, 2022

Currently in ActionScript, it's only possible to declare function signatures for methods and package level functions. It's not possible to declare signatures for variables and function paramters. The best you have is var foo:Function or function foo(fun:Function):Function{}.

This in my opinion is the biggest hole in the ActionScript type system. I have felt this lack for a very long time. It's very commonly felt in event handlers, but possibly a bigger issue is that it makes ActionScript a poor choice for functional-style programming.

If I had only one feature I could add to the language, it would be typed functions with signatures.

The exact syntax is less important than the type safety. My initial suggestion would be Vector style angle brackets with content like you'd use for an interface. Something like this: var fun:Function.<(ev:Event):void> or function foo(callback:Function.<(handler:IAsyncTask):IAsyncTask>):void{}.

@joshtynjala
Copy link
Member

joshtynjala commented Jan 18, 2022

This is definitely something I have always wanted to see in AS3.

If this were to be implemented, one thing that should be allowed is something like this:

var fun:Function.<(ev:Event):void> = function(ev:Object):void {};

To be clear, Event is a subclass of Object, so that function should be allowed for the same reason why you can assign an Event instance to a variable of type Object.

var obj:Object = new Event();

With return types, there's a similar situation, but instead of superclasses, subclasses would be allowed.

var fun:Function.<():Object> = function():Event {}

@greg-dove
Copy link
Contributor

var fun:Function.<(ev:Event):void> = function(ev:Object):void {};

@joshtynjala would that not be?:

var fun:Function.<(ev:Object):void> = function(ev:Event):void {};

@Harbs
Copy link
Contributor Author

Harbs commented Jan 18, 2022

No. I think the point was that you should be able to override the type restrictions by explicitly using Object. That's a general AS3 feature available elsewhere.

@greg-dove
Copy link
Contributor

No. I think the point was that you should be able to override the type restrictions by explicitly using Object. That's a general AS3 feature available elsewhere.

yes, but this: var fun:Function.<(ev:Event):void> is strongly typed to Event as a parameter, not Object. So it should accept function values with ev:EventSubclass, but not Object. That is generally how these things work, I think.

@Harbs
Copy link
Contributor Author

Harbs commented Jan 18, 2022

OK. I see what you mean. I'll leave it to Josh to answer for himself... 😉

@joshtynjala
Copy link
Member

joshtynjala commented Jan 18, 2022

As I was writing that, I wondered if it would be clear enough using Object, or if I should use more specific classes. I guess I should have been more specific after all.

Let me fix that. This should be allowed:

var fun:Function.<(ev:MouseEvent):void> = function(ev:Event):void {};

I don't have the types backwards.

Consider the following, which is allowed in AS3 code that exists today:

function myListener(event:Event):void {}
myListener(new MouseEvent());

This is why myListener should be allowed to be assigned to var fun:Function.<(ev:MouseEvent):void>. Because the type is Event, it can accept any subclass, including MouseEvent..

Function types in Haxe and TypeScript both work how I describe. Here's a TypeScript example:

let myListener1: (event: MouseEvent)=>void = function(event: Event) {} // no problem!
let myListener2: (event: Event)=>void = function(event: MouseEvent) {} // error!

@greg-dove
Copy link
Contributor

Thanks for the explanation, @joshtynjala, it's been a while since I used this stuff in Haxe, and I didn't use TypeScript yet.

I am used the declaration/assignment pattern of
var name:Type = value of Type or SubType

And it seems inverted here when looking at it (without thinking too deeply about it I guess).

So probably I am also getting confused about runtime vs. compiletime behavior here.

for
var fun:Function.<(ev:MouseEvent):void> = function(ev:Event):void {};

fun(new Event('blah')) will fail at compile time, which is the main point, I guess.

@joshtynjala
Copy link
Member

Yeah, it's kind of tricky. With function types, you need to think about what arguments get passed in when the function is called to understand what other function type can be assigned.

The other way around wouldn't work:

var fun:Function.<(ev:Event):void> = function(ev:MouseEvent):void {}; // this should error, but what if not?
fun(new FocusEvent()); // whoa, that's not a MouseEvent!

@Harbs
Copy link
Contributor Author

Harbs commented Jan 19, 2022

An aside: Why does Vector have the syntax Vector.<Foo> instead of Vector<Foo>? I've always found the extra dot weird and hard to remember...

@joshtynjala
Copy link
Member

You'd need to ask someone from Adobe about the full details, but I recall that there was some concern about whether Vector<Foo> might have some kind of potential syntax ambiguity, and they felt that it was safer to use Vector.<Foo> instead.

@hydroper
Copy link

hydroper commented Nov 20, 2023

I guess we should stick to the TypeScript form maybe? ES4 was fine too, but I am confused as to what is best. I have supported () => T in my parser also, but previously I have gone into function(...): T.

type F0 = () => void;
type F1 = (...a: Array) => void;

Also, ABC does not support function types, so the compiler should erase them at the output ABC in the meanwhile.

@hydroper
Copy link

hydroper commented Apr 11, 2024

Just to update, I've updated AS3Parser to comply with ECMAScript 4 syntax for function type expressions.

type F = function(): *
type F = function(Number=): *
type F = function(...[Number]): *
type F = function(...): *

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

4 participants