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

[WIP] Language proposal 0.2 #40

Closed
LPeter1997 opened this issue Jun 6, 2022 · 0 comments
Closed

[WIP] Language proposal 0.2 #40

LPeter1997 opened this issue Jun 6, 2022 · 0 comments
Labels
Design document This one came out from an idea but considers many cases and tries to prove the usabity

Comments

@LPeter1997
Copy link
Member

LPeter1997 commented Jun 6, 2022

Goal of the document

The goal of this document is to expand on the ideas laid out in the 0.1 proposal, to slowly work towards a complete language. Programs in the 0.1 proposal could already do simple calculations. While this proposal won't extend the capabilities much, it's working towards a language that is able to build up abstractions with user-defined types and generics.

Scope of the features

The primary topic of this proposal will be the type system:

  • Generics
  • Overloading
  • Type inference
  • User defined record types
  • For loops

Just like last time, the proposal implicitly defines the initial syntax.

Generic functions

Generic type parameters can be introduced after the function name between [...]. For example:

func second[T, U](x: T, y: U): U = y;

The rationale for leaving <> is that they are binary operators, which can really complicate the compiler in very undesirable ways - see what C++ goes through while parsing, or what Rust introduces syntactically not to make it painful. The simplest is just to take an operator that already comes in pairs, and [] is already used by languages like Scala.

Function overloading

While functions were already proposed in 0.1, function overloading was unspecified. I see no reason to disallow it, overloading should stay. A concrete function signature should bind stronger than a generic one. For example:

func foo[T](v: T): T = v; // (1)

func foo(v: int): int = v; // (2)

func main() {
    var a = foo(true); // (1) is called
    var b = foo(1); // (2) is called
}

This should be simple enough, but once subtyping comes into play, the rules might be complicated, we should keep that in mind. With the current rules we can already produce ambiguous calls - meaning it's not too hard to overcomplicate this system:

func foo[T](x: T, y: int) : int = 0; // (1)
func foo[T](x: bool, y: T): int = 0; // (2)

func main() {
    var a = foo(true, 1); // Both (1) and (2) match the 'same amount'
}

Type inference

One of the main strengths of the language should be a way stronger type-inference than what C# allows. A good example on a permissive - but not ML-level - type-inference system can be found in Rust: signatures must be fully typed, but inference can work freely in the function-local scope.

Return type inference

Functions with inline expressions should allow return-type inference:

func f1(x: int) = x; // OK, inferred to be (int) -> int
func f2() = Console.WriteLine(""); // OK, inferred to be () -> unit
func f3() { // ERROR: functions with a body need explicit return type,
            // assumed to be unit otherwise
    return 1;
}

Variable type inference

Variables can be declared without type, even when they do not get assigned a value immediately:

var x: int = 4; // OK, explicitly typed, value matches
var y = 4; // OK, inferred immediately to be int from the value
var z: int; // OK, explicitly typed
var w;
w = 1; // OK, inferred to be int from usage
var q; // ERROR: Could not infer type of the variable

Generic type argument inference

When a generic function matches the best for a function call, the generic types would be inferred, no need to specify call arguments, just like in C#:

func foo[T](v: T): T = v;

func main() {
    foo(3); // T = int
}

The generic arguments can be explicitly specified too, in case it can not be inferred (or for explicitness):

func foo[T](v: T): T = v;

func main() {
    foo[int](3);
}

Type placeholder

The _ can be used as a placeholder type, which can be useful when working with generics, only wanting to specify some of the type arguments:

func foo[T, U](a: T, b: U): T = v;

func main() {
    foo[_, bool](3, true);
}

The _ essentially means to create a type variable that will be inferred by the compiler. It can be used in any context, just like any other type.

Incomplete inference

An incomplete inference will result in an error. For example:

var q; // Without any usage of q

Any type is considered incomplete, that contains type variables.

User-defined record types

See #41 for the design documentation.

For loops

I believe a single for-each should be fine, if we can ease the range-creation a bit. Something like:

for (i in range(0, 10)) {
    WriteLine("Hello, " + i);
}

The type could be specified after the variable name, like for (i: int in range(0, 10)) .... The variable would be a val, meaning it can't be reassigned.

Under the hood, it would be desugared into a while-loop, similarly to C#:

for (i in range(0, 10)) {
    WriteLine("Hello, " + i);
}
// Becomes
var enumerator = range(0, 10).GetEnumerator();
while (enumerator.MoveNext()) {
    val i = enumerator.Current;
    WriteLine("Hello, " + i);
}

Future ideas

Ideas that came up while writing this proposal:

  • named arguments for function calls
  • named explicit generic arguments
  • optional arguments (maybe even with non-constant expressions?)
  • optional generic type arguments
@LPeter1997 LPeter1997 added the Design document This one came out from an idea but considers many cases and tries to prove the usabity label Jun 6, 2022
@LPeter1997 LPeter1997 pinned this issue Jun 6, 2022
@LPeter1997 LPeter1997 changed the title Language proposal 0.2 [WIP] Language proposal 0.2 Jun 7, 2022
@LPeter1997 LPeter1997 unpinned this issue Aug 31, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design document This one came out from an idea but considers many cases and tries to prove the usabity
Projects
None yet
Development

No branches or pull requests

1 participant