chharvey / counterpoint

A robust programming language.
GNU Affero General Public License v3.0
2 stars 0 forks source link

Type Claim Statements #83

Open chharvey opened 2 years ago

chharvey commented 2 years ago

A type claim declaration is a type claim for a variable at the block level.

claim expr: T;

This is a statement, not an expression, and it applies to the scope of the whole block. After a variable expr has been declared, we can use this statement to claim that it has type T throughout the block. This is convenient because we don’t have to claim the expression everywhere it’s used in the block.

The code below uses type claim expressions (#82) to override the type-checker’s typing of item.1. But type claim expressions need to be used every time the variable is referenced.

let item: mutable [str, int | str] = ['apples', 42];
'''
    Clerk:    How many {{ item.0 }} would you like?
    Customer: {{ <int>item.1 }} please.
    Clerk:    Wow, {{ <int>item.1 }} is a lot!
''';

One way to simplify this would be to declare a new variable:

let item: mutable [str, int | str] = ['apples', 42];
let quantity: int = <int>item.1;
'''
    Clerk:    How many {{ item.0 }} would you like?
    Customer: {{ quantity }} please.
    Clerk:    Wow, {{ quantity }} is a lot!
''';

But a new variable could take up space on the runtime machine. The only purpose of quantity is to make a type claim, so it’s not necessary at runtime.

Instead, we should claim the expression’s type in a claim statement. Type claims take place only in the compiler, so no memory is wasted.

let item: mutable [str, int | str] = ['apples', 42];
claim item.1: int;
'''
    Clerk:    How many {{ item.0 }} would you like?
    Customer: {{ item.1 }} please.
    Clerk:    Wow, {{ item.1 }} is a lot!
''';
chharvey commented 2 years ago

This PR also changes the syntax for reassignment statements (#13): it prepends the assignment with the keyword set.

let unfixed my_var = 'Hello, world!';
my_var;                               %== 'Hello, world!'
set my_var = '¡Hola, mundo!';
my_var;                               %== '¡Hola, mundo!'

This is a breaking change. The code my_var = '¡Hola, mundo!'; is no longer well-formed or valid.

There are several reasons why this decision was made, but it all boils down to easier parsing. We want a syntax that won’t cause reduce-reduce conflicts in an LR1 parser.

For one example, if destructuring syntax uses parentheses, then the statement

(a, b) = c;

would look very similar to the function expression

(a, b) => c;

and would confuse the parser.

Or, if destructuring uses brackets, then the statement

[a, b] = c;

would look too close to the tuple

[a, b];

So by prepending reassignment statements with set, we can eliminate these conflicts.

set (a, b) = c;
% (or)
set [a, b] = c;