ECMAScript proposal: Hash Comments (replacement for Type Annotations)

Hi! This is my first time attempting to submit a proposal to TC39. I'm looking not just for champions but also collaborators who can help make this a more solid proposal.

Proposal is here: GitHub - matthew-dean/proposal-hash-comments: ECMAScript proposal for annotation syntax, useful for types

Thanks for your help!

1 Like

This proposal shares every flaw of the proposal it builds on top of (allowing meaningless tokens), and thus my basis for opposition to it becoming standard is the same as the basis for my ongoing vocal opposition to the Type Annotations proposal. The one thing I like more about your proposal is that everyone would hate it equally, seeing as you would be asking all TS users to give up their syntax, even the ones who are using JSDoc.

That said, don't mistake me for a pessimist either. You clearly have an idea for a programming language extended from Javascript (such as TS is), and you should go make that idea real. It's one of the most challenging and rewarding experiences you can have in building software!

1 Like

Haha well that’s honest, which I appreciate. Ironically, I’ve also been a big vocal opponent of the type annotations proposal, and part of why I wanted to get this out there was to help illustrate why the original proposal was so shortsighted in terms of syntax.

But, as far as the critique that it allows meaningless tokens, in some sense, that seems like a silly critique, because the same would apply to any type of comment. All comments have a start and end sequence, and while the end of a hash comment has variable conditions vs the fixed conditions of other comments, it doesn’t render the contents of other comments any more meaningful.

I think what you may have gotten distracted by are of the possible use cases in a type system, as an effort to address what type annotations was attempting to do.

But at the end of the day, this proposal could just be summarized as:

  1. Recognize that JavaScript already had 3 existing comment syntaxes, not two. So it expands the third. Expand the hash comment syntax, which starts with ‘#’ and has some unique conditions for comment end
  2. If you’re familiar with CSS, the parsing rules are very similar (in concept) to custom property values, so the concept has already been tested and widely used

It’s really not more complicated than that, any more than /* * / and // comments are complicated (or are “meaningless tokens”?). Each of those types have different “comment end” rules, and the same is here, but starting with # instead of // or / *

Maybe it should be separated into just the comment syntax, as a generic concept, with separate documents as to how it could be useful?

Also, to be fair, I have also considered that TypeScript users might hate this (although being forced to use JSDoc seems way more annoying) and I did consider that maybe this could be its own meta-language with a different approach to types, but I just wanted to put that out there.

Thanks for your feedback!

1 Like

(it has more than two - // comment, /** comment */, <!-- comment, --> comment, and # at the start of a file, at the least)

2 Likes

A lot of committee feedback for the existing proposal was that they need to let go of the idea of being so backwards compatible with TypeScript and be willing to explore other options that didn't require so many grammar productions. Unfortunately, the champions seem reluctant to heed this, which is a shame. It doesn't give me high hopes for that existing proposal.

@matthew-dean's idea, IMO, strikes a good balance with what was actually being asked from the champions.

On a different note - I wonder if this proposed syntax would have any issues with the existing JavaScript syntax of doing #something in this to check for the existence of a private field - that might be another place that would require special parsing rules maybe.

2 Likes

Agreed. Even if there were special parsing rules to make it technically work the visual similarity to private fields seems that it would make this difficult to teach and read. Such as the example from the readme.

class Person {
  #name #string; // a private field of `#name`, commented with `#string`
}
2 Likes

I know it's been discussed before, but we keep going round in circles... JS needs some kind of binary format (basically, an efficiently encoded AST) that languages like TypeScript can target.

That binary format should be where we add support for stuff like strict or static types, though they should be real types (that JS engines can use, similar to WebAssembly).

Language evolution for the Web should mainly happen in languages that either compile to Wasm or to a new JS binary format (or some combination of the two). JavaScript already does far too much.

1 Like

@aclaymore @theScottyJam Yeah, I feel like private fields adopting this syntax robbed so many proposals when it landed.

I wonder if the only workable solution is requiring angle brackets always. Or some other additional character?:

class Person {
  #name #<string>
}
class Person {
  #name #|string
}
class Person {
  #name ##string
}
class Person {
  #name #:string
}

## is nice because it's fast and is a little like // So maybe it's like:

  • ##ident - with identifier
  • #! - with special character
  • #<a longer sequence with blocks (like <this>)>
2 Likes

There are several issues in the type annotations repo proposing new comment forms (e.g., e.g.).

I suggest reading through those and participating in the conversation there, since you are mostly trying to solve the same problem.

1 Like

@bakkot Thanks for your reply! As to those issues, I'm aware of many of those, and have proposed and contributed to some of them.

I think most of those proposals, including past proposals, suffer from trying to work backwards from TypeScript, to some degree, and aren't really general-purpose.

In other words, many start with assumptions like:

  1. wanting to put : to assign a type - even though TypeScript or other type systems work "okay-ish" with this syntax, it has specific places where it conflicts with JavaScript, where : is already used to assign a value
  2. generally keeping the same "order" of type annotations that TypeScript has established

That's why I'm proposing the inverse - coming up with a general hash-comment syntax with some simple parsing rules, and then proving out that it can annotate ergonomically and expressively enough to establish type- and type-aware features.

I don't disagree that such a proposal (like @conartist6 alluded to) would be less attractive to TypeScript the more that it would deviate from TypeScript, but I think matching TypeScript as closely as possible shoudl be a non-goal. The goal (IMO) should be to have an ergonomic comment syntax that can be less verbose than wrapping in /* */, and has comment-end logic that isn't just "end of line" like //.

So, I think what everyone is circling around doesn't really have to do with types at all, and even Microsoft's proposal doesn't make that clear. What people are circling around is that the utility of JavaScript's comment syntax is limited and un-ergonomic for specific use-cases, enough that new languages are developed with new syntax rather than leveraging a special "comment form" that can ergonomically annotate markers that a meta-language might want to use. JSDoc is the current solution for that, but it's extremely verbose, and of course becomes very unwieldy when working with function generics or non-null assertions.

So, that's what I'm proposing here - which I could also make more clear - an additional comment form that is both flexible for very long "chunks" of annotations, but also can "auto-close" with some basic rules. And is less weird than a proposal like :: (which exists to make forms like :: string even if :: doesn't really make sense, semantically, with JavaScript. JavaScript already has "hashbang comments", where #! is already a comment start, so starting with # (or using #{special_character}) as a generalized form is treading less on new territory.

Another reason I didn't add to that repo in the form of a new issue is that the proposal owners thus far have shown little interest in looking at anything that deviates from TypeScript, so I just fundamentally feel like that proposal itself is a dead-end.

@bakkot EDIT: it looks like you're someone else who put a lot of thought into alternate syntax forms, so I'd be happy to explore some variations of hash comment syntax with you.

1 Like

I wonder if the simple rules could be something like:

  1. A # followed by : allows an additional identifier e.g. #:Foo
  2. A # followed by < allows nested, matching blocks, containing known and unknown tokens e.g. #<a more extensive comment> or #<Foo>
  3. In the outer # statement, ! or ? is allowed as an additional token e.g. #:string? or #!
  4. In the first line, #! consumes the entire line

That said, for #1, you're really only saving one character once you require an additional character to disambiguate from private fields :thinking:

If you required #<> for identifiers, it might be simpler, like:

  1. #<Foo>
  2. #<a more extensive comment>
  3. #<string>? #? #!

What you could also do is, like CSS, allow other outer block start/ends (while explicitly ommitting #[ and #{ as valid to not trample on records and tuples).

e.g.

  1. #(string)
  2. #<T extends Foo>
  3. #(string)? #? #!
  4. #|maybe| ? :man_shrugging:

and e.g.

#(interface MyInterface {
  name: string
  age: number
})

and another example outside of TypeScript, just to not focus on TypeScript

// meaningful to some bundler
#|pure| function() {}

// meaningful to some linter
#(ignore-line) () => {}

// meaningful to a transpiler without hacking decorator as a transpilation signal
#|reactive|
let aNumber = 1
1 Like

The thing you're talking about is basically the "token soup" discussed at some length in the issues and notes already. I admire the spirit, but I really encourage you to read through the existing discussions before setting out to invent something new.

They've actually spent quite a lot of time talking about various syntax alternatives which aren't exactly TypeScript syntax. More to the point, though, it's also where basically all discussion of ideas in this space has taken place, because at this early stage the proposal might yet grow in many different directions. "I want this proposal to go in a different direction" is still an appropriate comment to make as an issue on an existing proposal.

1 Like

@bakkot Thanks for that! I rewrote the proposal to solve the token soup problem, but I'll chew on it some more about possibly posting it as a new issue on that repo.

Again TS itself solves every single problem. It isn't a token soup. The types mean something.

We don't want to create new problems so we should just be trying to support the one absolutely proven-beyond-doubt pattern here: language extension

I agree with your intentions, but not with the details. Take a look at the reception that JS-Zero/JS-Sugar got, it's not just controversial, it seems net negative.

See also (off-topic): "deprecate-js" proposal by Rudxain · Pull Request #9 · Rudxain/blog · GitHub

Was gonna reply, but I'll just DM instead to avoid steering the conversation more off topic