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

Suggestion: compact notation for an array of string literals #742

Open
gwhitney opened this issue Sep 18, 2023 · 9 comments
Open

Suggestion: compact notation for an array of string literals #742

gwhitney opened this issue Sep 18, 2023 · 9 comments
Labels
proposal Proposal or discussion about a significant language feature

Comments

@gwhitney
Copy link

It's not that uncommon that I want a list of allowed keys or something like that. So not too infrequently I find myself writing

keys := 'skeleton blank house cipher car'.split ' '

which looks a bit goofy, but it's significantly pleasanter to type than

keys := ['skeleton', 'blank', 'house', 'cipher', 'car']

because of all those pinky and ring-finger keystrokes.

LiveScript had a compact notation for this, I think it was

keys = <[skeleton blank house cipher car]>

I don't love the <[ ... ]> as it looks sort of JSX-y, but I do think a compact notation for arrays of literal strings that don't contain whitespace would be pleasant/handy.

Brainstorming some options:

keys := [''skeleton blank house cipher car''] // it's kind of quote-y, riffs on triple quote
choices := ['|'option|choice|has space|freedom] // provides a place for the delimiter
answers := [[[correct dumb thoughtful wrong]]] // when in doubt, triple it; but it does shadow
// an array of one element, which is an array of one element, which is an array of one element
// produced by a chain of function calls. So that's likely unacceptable.

Anyhow, just a thought.

@STRd6
Copy link
Contributor

STRd6 commented Sep 18, 2023

Neat idea! Some random thoughts:

  • Operator overloading is something we'd like in the future. Maybe "skeleton blank house cipher car"|" " -> "skeleton blank house cipher car".split(" "). We could have | with a string rhs to convert to split until we have full support for binary operator customization.
  • For static strings known at compile time we could even generate proper TS types for the split.

@edemaine
Copy link
Collaborator

Another fun thing we could do is transpile 'skeleton blank house cipher car'.split ' ' to ['skeleton', 'blank', 'house', 'cipher', 'car'], as an optimization, similar to how [0..9] transpiles. This doesn't solve the beauty/notation though.

Another way to write this today would be ssv`skeleton blank house cipher car` for an appropriate function ssv (named to mean space-separated data). I agree it'd be nice to have something built-in though.

@STRd6 STRd6 added the proposal Proposal or discussion about a significant language feature label Sep 18, 2023
@gwhitney
Copy link
Author

Another way to write this today would be

True, and I guess you could type ssv so

keys := ssv`skeleton blank etc`

would get the literal type ['skeleton', 'blank', 'etc'], without too much difficulty. I should probably write that way in the meantime.

Another random syntax possibility:

keys := []skeleton blank house cipher car[]

I'm not saying any of the suggested syntaxes are perfect, but some seem plausibly acceptable. This one is the most compact I've thought of that is currently a parse error and therefore potentially up for grabs.

@edemaine
Copy link
Collaborator

By the way, it's perhaps useful to reflect on other languages that have this feature:

  • Perl: qw(skeleton blank house cipher car) is shorthand for ("skeleton", "blank", "house", "cipher", "car"). You can also use []s or any matching character like qw!...! or qw/.../.
  • Ruby: %w(skeleton blank house cipher car) is shorthand for ["skeleton", "blank", "house", "cipher", "car"]. You can also use []s or any matching character like %w!...! or %w/.../.
  • Bash/Zsh: (skeleton blank house cipher car) is equivalent to ("skeleton" "blank" "house" "cipher" "car") (thanks to quoting rules)

qw and %w do look a lot like template syntax, but there's the nifty idea of having arbitrary delimiters (like LaTeX's \verb) which is nice if your strings have particular characters. Admittedly we're breaking on whitespace, so that's already a bit restrictive.

Inspired by your last idea, I wonder about this syntax: []`skeleton blank house cipher car`, as a generalization of template syntax... Although I'm not sure what ${} expansion would mean, especially if this is done at compile time, so maybe this is a false analog... Though we could define some reasonable meaning, e.g.:

[]`skeleton ${key} x${key} ${...more}`  ["skeleton", key, `x${key}`, ...more]

(though perhaps I'm getting carried away)

@gwhitney
Copy link
Author

gwhitney commented Sep 20, 2023

I am actually pretty comfortable with

[]`a b c`

I think it's pretty suggestive of "make this literal into an array in the most obvious way". Covers my typical use case pretty nicely.

I suppose to avoid the specialness of breaking on whitespace, making it just a default, it could be nice to allow e.g.,

[|]`option A|choice B`

Or maybe better

['|']`option A|choice B`

So that

[foo]`stuff`

really just becomes syntactic sugar for

`stuff`.split(foo)

with a new default of ' ' if foo is not specified (which frankly I am surprised JavaScript does not already allow in split).

@edemaine
Copy link
Collaborator

Nice, I like that generalization!

I think the default should be /\s+/, not ' ', matching the default for Python's split. (I agree it's annoying that it's not the default in JavaScript.) In the special case of the default, I think it also makes sense to remove an empty first or last item, so that []` a b c ` still produces ['a', 'b', 'c']. This is especially useful for multiple lines:

[]`
  option1
  option2
  option3
`

@gwhitney
Copy link
Author

True, and I guess you could type ssv so

 keys := ssv`skeleton blank etc`

would get the literal type ['skeleton', 'blank', 'etc'], without too much difficulty

Well actually, I spoke too soon. I was going to contribute to this discussion some working correctly-typed code for ssv (that would split on /s+/) and also support

ssv('|')`My values|have spaces`
ssv(/[.]+/)`I...like ellipses... very much!`

mostly because I would use it anyway and possibly it could provide a compilation target for

[]`The  standard \n thing makes \t 6 words.`
[' ']`Only break \n on spaces to get an array of 12 elements.`
[/[{}() ]/]`You{[bracket buster,] you!}`

But then I ran into microsoft/TypeScript#33304. (And very gratifyingly/amusingly one of the comments on that issue is someone explicitly trying to produce a tagged template replicating ruby %w[foo bar zaz] in Typescript. So we are in fact onto something...)

Oops, who knew? So I have given up on this micro-project for the time being. But in some sense it would make it even more useful/cool if Civet did implement this latest []-template literal notation as just above, which I get the sense the two of you like best from the options floated here, in a type-safe way today.

@gwhitney
Copy link
Author

P.S. About the meaning of interpolation in

[foo]`Some ${substituted} x${pressions} to ponder${bang}`

I personally think that since the usual backticks just deal in strings so this feels "stringy" and feels mostly about literal arrays of literal strings, this syntax should just operate on the string level and so the above should precisely mean

`Some ${substituted} x${pressions} to ponder${bang}`.split(foo)

with the caveat of when foo is absent there's the special-case behavior of splitting on /\s+/ and discarding empty first and last chunks if present.

Moreover, I would suggest it is fine to type as string[] when foo or any interpolation is present. Any finer typing, e.g. if all of the interpolated variables are known constants and/or if foo is just a literal string, say, would be icing on the cake. Re this, note that in TypeScript today

const foo = `bar baz`  // types as 'bar baz'
const quux = `quince ${foo}` // types as string

@danielbayley
Copy link
Contributor

danielbayley commented Feb 1, 2024

  • Ruby: %w(skeleton blank house cipher car) is shorthand for ["skeleton", "blank", "house", "cipher", "car"]. You can also use []s or any matching character like %w!...! or %w/.../.

@edemaine @gwhitney @STRd6 +1 vote for this!

I use %w[a b c] all the time in Ruby… Also, note that (uppercase) %W[a #{variable} c] allows interpolation, and also there is %d[1 2 3] for an array of integers, amongst other % markers…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
proposal Proposal or discussion about a significant language feature
Projects
None yet
Development

No branches or pull requests

4 participants