C isn’t too far off either (no explicit concatenation – the preprocessor concatenates string literals):
const char my_string[] =
"First line.\n"
" Second line with internal indentation.\n"
;
And I used to write printf statements like this:
printf("a=%d b=%zu c=%02x"
, a
, b
, c
);
Sadly, there is no way any existing autoformatter is going to accept any of that. Maybe it’s fixable by writing yet another autoformatter, but I feel I always know better than the autoformatter, and never appreciated what it did to my code, so I wouldn’t have liked to contribute to such a problem.
For what it’s worth, I was writing quite a bit of LeetCode in OmniOutliner of all things, a few months back. I could basically write JavaScript in outline format, copy/paste into Sublime, and it’d be formatted pretty well. I’m still really keen on the idea of outlining code in OmniOutliner, and transforming it into real source (though mostly, I just stick to IntelliJ).
2 things stood out:
the closing } for a function would basically have to be nested inside it, so it can all collapse, otherwise you have 2 consecutive items “function foo(..) {” with all the code in it, plus a “}” to follow—this looks weird in code, but makes sense in the outline
comments are nice when they’re in a separate column, even though I was still writing out “// …” instead of “…”
I think you have to fully adopt a lisp like syntax to get away with not treating the white space differently in the context of the list. Say you skip the “white space as delimiter” in the case of [f()g()] you could argue there are no delimiters. [(one)(two)] seems like it should work as well. But is [x - y] equivalent to [x, -y] or [x-y]? And for my parens example is one(two) or one,two?
You can’t even always disambiguate with parens, if I mean x, -y and write [(x)(-y)] it can still be interpreted as x(-y). And if x (-y) means something different inside a list versus out the space is acting as a delimiter not just a token separator.
I’m using spaces for brevity but the same argument applies to new lines, imo. if
[a-b]
and
[a
-b]
are different lists the new line is serving as a delimiter for the list, not just token separation.
You don’t need to if your grammar has unambiguous ends. For example in a language I made you can have quite complex expressions with no parens. Of course it isn’t necessary a good idea, it can confuse readers if you don’t format the code well.
log-level = cond:[
env == "dev" "warn"
"info"]
I chose to keep the = between the keys and values for dictionaries but even that is mostly unnecessary (but it does allow a local a = 5 syntax without making local a keyword)
Yeah, you can do it. IIUC ECL avoids the [x-y] problem because x-y is a single identifier, and x - y is an expression consistently. It avoids the one(two) problem by having the : for function application. So its lists really don’t have delimiters. I think you can also “solve” - by not reusing the same symbol for negation and subtraction.
Yeah, operators that can be unary or binary is the enemy of this approach. I think right now ECL doesn’t have a negation operator. You need to do 0 - x. -1 is parsed as one token. But using a dedicated unary negation symbol would solve this.
It’s really great, and it’s probably better than trailing-comma separated values, but I will literally never write code with a leading comma. It looks stupid, and I can’t get over how much I hate seeing it. Position-independent symbols (like the dot used in the article) I would find completely palatable, though.
Did you just invent value-separated commas?
The article’s suggested multiline string syntax is similar to what Zig has:
This is really nice because you can align it properly with surrounding code. I hope other languages adopt this.
Curious if this has any obvious advantages or deficiencies relative to nix’s indented strings, which I find pretty aesthetically pleasing.
edit for illustration:
C isn’t too far off either (no explicit concatenation – the preprocessor concatenates string literals):
And I used to write printf statements like this:
Sadly, there is no way any existing autoformatter is going to accept any of that. Maybe it’s fixable by writing yet another autoformatter, but I feel I always know better than the autoformatter, and never appreciated what it did to my code, so I wouldn’t have liked to contribute to such a problem.
It appears to work a bit better for vertical formats than horizontal ones. But I do like the comma-first style—I may adapt that.
An interesting write-up.
For what it’s worth, I was writing quite a bit of LeetCode in OmniOutliner of all things, a few months back. I could basically write JavaScript in outline format, copy/paste into Sublime, and it’d be formatted pretty well. I’m still really keen on the idea of outlining code in OmniOutliner, and transforming it into real source (though mostly, I just stick to IntelliJ).
2 things stood out:
the closing } for a function would basically have to be nested inside it, so it can all collapse, otherwise you have 2 consecutive items “function foo(..) {” with all the code in it, plus a “}” to follow—this looks weird in code, but makes sense in the outline
comments are nice when they’re in a separate column, even though I was still writing out “// …” instead of “…”
Why do we need delimiters at all?
That has delimiters, they’re just contiguous runs of white space.
[onetwothree]
would be without delimiters, compare[one,two,three]
.Most programmind languages use a model where whitespace is used to separate tokens and otherwise ignored, so
f()g()
is the same asf() g()
.I think you have to fully adopt a lisp like syntax to get away with not treating the white space differently in the context of the list. Say you skip the “white space as delimiter” in the case of
[f()g()]
you could argue there are no delimiters.[(one)(two)]
seems like it should work as well. But is[x - y]
equivalent to[x, -y]
or[x-y]
? And for my parens example isone(two)
orone,two
?You can’t even always disambiguate with parens, if I mean
x, -y
and write[(x)(-y)]
it can still be interpreted asx(-y)
. And ifx (-y)
means something different inside a list versus out the space is acting as a delimiter not just a token separator.I’m using spaces for brevity but the same argument applies to new lines, imo. if
and
are different lists the new line is serving as a delimiter for the list, not just token separation.
You don’t need to if your grammar has unambiguous ends. For example in a language I made you can have quite complex expressions with no parens. Of course it isn’t necessary a good idea, it can confuse readers if you don’t format the code well.
I chose to keep the
=
between the keys and values for dictionaries but even that is mostly unnecessary (but it does allow alocal a = 5
syntax without makinglocal
a keyword)https://gitlab.com/kevincox/ecl
Yeah, you can do it. IIUC ECL avoids the
[x-y]
problem because x-y is a single identifier, andx - y
is an expression consistently. It avoids theone(two)
problem by having the : for function application. So its lists really don’t have delimiters. I think you can also “solve” - by not reusing the same symbol for negation and subtraction.Yeah, operators that can be unary or binary is the enemy of this approach. I think right now ECL doesn’t have a negation operator. You need to do
0 - x
.-1
is parsed as one token. But using a dedicated unary negation symbol would solve this.this is what it would be like with no delimiters
but this is ambiguous
A delightfully through-the-looking-glass perspective. I should play with this idea more someday. <3
It’s really great, and it’s probably better than trailing-comma separated values, but I will literally never write code with a leading comma. It looks stupid, and I can’t get over how much I hate seeing it. Position-independent symbols (like the dot used in the article) I would find completely palatable, though.
That’s an excellent idea