eclipse-archived / ceylon

The Ceylon compiler, language module, and command line tools
http://ceylon-lang.org
Apache License 2.0
399 stars 62 forks source link

TypeScript string types #6590

Open lucaswerkmeister opened 8 years ago

lucaswerkmeister commented 8 years ago

TypeScript has “string types”: "foo" is a perfectly ordinary type, and so is "foo" | "bar" | number.

Their two main uses seem to be:

  1. Union of string types as “enum”:

    type ScrollBehavior = "auto" | "instant" | "smooth";
  2. Overloads:

       createElement(tagName: "a"): HTMLAnchorElement;
       createElement(tagName: "applet"): HTMLAppletElement;
       createElement(tagName: "area"): HTMLAreaElement;
       createElement(tagName: "audio"): HTMLAudioElement;
       createElement(tagName: "base"): HTMLBaseElement;
       // many, many more…
       createElement(tagName: "xmp"): HTMLPreElement;
       createElement(tagName: string): HTMLElement; // fallback

The first case could be converted to the equivalent of:

shared class ScrollBehavior of auto | instant | smooth {
    shared new auto {}
    shared new instant {}
    shared new smooth {}
}

Where the backend would erase ScrollBehavior.auto to "auto", and dre$$ would know that the type ScrollBehavior is really just String. (Note: these “enums” don’t always get a type alias; we might for example have to take the name from the parameter whose type they are, i. e. scrollBehavior: "auto" | "instant" | "smooth".)

But for the second case, we need them to be actual types. So I would propose this instead:

shared object a {}
shared object applet {}
shared object area {}
// ...

And the overloads would map to:

HTMLAnchorElement createElement(\Ia tagName);
HTMLAppletElement createEleemnt(\Iapplet tagName);
// ...

The backend would still make sure that all of these objects are erased to their string literal, and dre$$ would know that this string value is the only allowed value for that type.

Of course, we would have to make sure that these names do not collide with any pre-existing module members; where necessary, we would disambiguate them with aString, aStringType, or something similar. (However, it’s no problem if a string type appears multiple times: just reuse the object.)

For string types that don’t happen to be valid identifiers, we would need to either escape the name or just invent one (stringType1). To make sure that this isn’t necessary too often, we should check type aliases first: the user could then add the “helper alias”

type SvgNamespace = "http://www.w3.org/2000/svg";

and we would map that string type in createElementNS to SvgNamespace instead of a made-up name. (This is also how we’ll make structural types not suck: give them names with aliases.)

Any comments or suggestions?

gavinking commented 8 years ago

@lucaswerkmeister Do you always have a type declaration whenever you have a function overloaded by string types?

lucaswerkmeister commented 8 years ago

@gavinking no, for the overloading usecase I haven’t seen that at all. I don’t see how it would make sense, either – where would you use that declaration? Each overloaded definition only uses one of the string types, not the union.

lucaswerkmeister commented 8 years ago

And by the way, here’s an example where string types are used as a sort of “enum”, but without a type alias:

interface String {
    normalize(form: "NFC" | "NFD" | "NFKC" | "NFKD"): string;
    // ...
}
gavinking commented 8 years ago

Oh, I see, I misread.

gavinking commented 8 years ago

FTR, I would not be totally implacably against adding symbols and symbol types to the language, that is, something like the following:

alias ScrollBehavior = $Auto | $Instant | $Smooth;

ScrollBehavior scrollBehavior = $auto;

And:

HTMLAnchorElement createElement($A tagName);
HTMLAppletElement createElement($Applet tagName);

HTMLAnchorElement a = createElement($a);

Or something like that.

Reminds me of SmallTalk :-)

lucaswerkmeister commented 8 years ago

I don’t know, I don’t feel like string types are very useful outside of modeling pre-existing APIs. I don’t think we need to add these symbols to Ceylon.