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

Syntactical control knobs for variance, nullability, structural vs nominal, etc #15

Open
samuelgoto opened this issue Jul 22, 2017 · 0 comments

Comments

@samuelgoto
Copy link
Owner

samuelgoto commented Jul 22, 2017

It would be great if the standard type system could be a super set of the three type systems so that all of them could use it as a compilation target without losing typing information information.

Along the same lines of the C# in and out operator that controls variance in collections, here is an early exploration of what perhaps adding extra syntax to the type system could help us find a super set of the features of each.

Nullability

The ! operator, applied to a type, makes it NOT nullable. The ? operator, makes it nullable along the lines of this.

function foo(duck: !Duck) {
  // duck makes it NOT nullable
}

function foo(duck: ?Duck) {
  // duck makes it NULLABLE
}

nominal versus structural types

We could add a ~ operator, called the "kindaof" operator (makes a "so so" floating hands) that, when applied to a type, makes it structural as opposed to nominal (and, similarly, a = operator, that makes it nominal). For example:

// treats duck as "a structural Duck"-like type
function foo(duck: Duck~ ) {
  duck.quack();
}

// This takes duck as a "nominal" duck
function foo(duck: Duck=) {
  duck.quack();
}

// ~Foo is a structural Foo.
// NOTE(goto): maybe use @annotators, instead, like @structural interface Foo {}?
interface ~Foo { 
  duck();
}

// =Foo is a nominal Foo.
// NOTE(goto): maybe use @annotators, instead, like @nominal interface Foo {}?
interface =Foo {
  duck();
}

variance in collections

Along the same lines of the C# in and out operator, one could control the variance of a type explicitly via the in and out operator.

function foo(ducks: Array<in Duck>) {
  // may "write" do ducks
}

function foo(ducks: Array<out Duck>) {
  // only "reads" ducks
}

TODO(dimvar): help me come up with an example that @gbracha said.

// Takes duck in a contravariant way
function foo(duck: in Duck) {

}

// Takes duck in a covariant way
function foo(duck: out Duck) {

}

var contravariantVar: Array<in Duck> = ["foo", "bar"];
var covariantVar: Array<out Duck> = ["foo", "bar"];

Optionality

function foo(?a: Duck) {
  // makes a OPTIONAL
}

enums?

Worst case configuration

In the worst case one want to control every single aspect of the type with the modifiers, which can be very ugly to type. Here is what it could look like:

function(?a: in !Duck~) {
  // a is a Duck that is:
  // - optional
  // - not nullable
  // - covariant
  // - structural
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant