typst / typst/typst

Inconsistency with paren patterns in let-statements vs. assignment

Open
#5,351 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug syntax
Dominant language
Rust
Stars
56.1k
Forks
1.7k
Avg merge
3d 10h
Merged PRs (30d)
22

Description

Description

I initially brought this up in the parser refactor in this comment, but am breaking it out into a new issue.

Arrow functions allow you to optionally parenthesize single arguments: we allow both x => x and (x) => x with the same meaning. We'll say the second one is using "raw parens" (raw, as opposed to also including commas/colons/etc.). For arrow functions, this is fine and should not change.

We also allow raw parens in let-statements, where let x = y and let (x) = y having the same meaning. Only adding an explicit comma, colon, or spread would cause it to destructure an array/dict.
Destructuring paren statements:
Array: let (x,) = (y,) or let (..abc) = (a,b,c)
Dict: let (key: x) = (key: y) or let (x,) = (x: y) or let (: ..abc) = (a: 1, b: 2, c: 3)

Then we also allow the same destructuring syntax in variable assignments, e.g. (x,) = (y,).

However we do not currently allow raw parens in assignments. x = y is allowed, but not (x) = y. This is inconsistent and should be resolved.

My pick

I think we should start to disallow raw parens in both assignments and let-statements, but keep arrow-functions as-is.

My feeling is that allowing raw parens encourages users to write subtly incorrect code, that might be syntactically allowed, but won't do what they expect at runtime. Ex: intending to desctructure (x) = (7,), but getting an error when you try to use x as a scalar because it is still an array. If we error earlier (at parse time), we make it easier to avoid mistakes and remove the possibility.

If we do disallow raw parens, we should give the user a helpful error message, e.g. "add a comma inside the parens to destructure an array or dict".

Disallowing raw parens also gives us backwards compatibility if we want to give them an actual meaning in the future.

Other options

We could also:

  1. Say that raw parens act like array destructors with an implicit comma — but this is inconsistent with the array constructor syntax, since an explicit comma is required to construct an array.

  2. Allow raw parens to work on both assignment and let-statements — but this allows multiple ways to write the same thing, and adds ambiguity to the normal context. I wouldn't want to make a formatter rule to choose between (_) = y and _ = y for some coding style.

  3. Either disallow or require raw parens for arrow functions — but here the raw parens denote arguments, not array/dict destructuring (unless you double the parentheses). Requiring them feels like a syntactic burden, and disallowing them would be inconsistent with the let func(args) syntax.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the parser refactor discussion linked from the issue and compare the current handling of raw parentheses in let-statements, assignments, and arrow functions. Decide whether raw parens should be rejected in let-statements and assignments while remaining valid for arrow functions, then verify the proposed examples and helpful parse-error wording.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.