The idea is that instead of having to learn tens of different syntactic constructs with subtle and often arbitrary differences, you just have parentheses and use them to build everything.
This is such a undervalued benefit, once you've learned s-expressions, you can basically learn a bunch of languages without having to learn completely new syntax. It'll be slightly different, with different idioms and names, but a hell of a lot easier than doing the same across every "It's like C but 50% of the syntax is different actually" language out there, which is most of them.
Is the syntax really the stumbling block for most languages? Would Rust's lifetimes or Swift's isolation rules be easier if they used more parens? Are the scoping rule differences between Emacs Lisp and Scheme easier to comprehend because the syntax is similar?
Yes, a commonly occurring stumbling block for me is trying to use one language's syntax while actually programming in another, especially when it comes to all the Algol/C-like language, I probably mix things on a daily basis.
The concepts would be easier to grok up front if they just used normal function calls instead of "And now for this special syntax that only exists for this particular feature" which just adds more things to remember, instead of just the concepts themselves.
well sometimes you get complaints in particular languages that someone has written code like they are a Java programmer, or their code is not rubyish enough, or pythonic enough, and so on.
So often people coming from one linguistic syntactical style express themselves in that style which makes their code in the new language less understandable or maintainable.
Yes it is, because as soon as programmers step out of the most basic language level (which is kinda similar in most mainstream languages) there's a bunch of wildly different concepts, with wildly different ways of writing them. Writing them in isolation might be manageable, but it's combining them effectively that gets hairy very quickly, unless one is very experienced in said language. But then, translating that to OTHER languages becomes a bar that is too high!
The kind of subtle difference I’m talking about is that in C, you have to put a semicolon after struct {…} and do {…} while (…), but not after other curly brace constructs. What would be the analogue in Janet?
The first one is pretty C-specific and for example doesn’t exist in Java. Similarly for the second one, the reason is that `while` is used for two different constructs, which for example isn’t the case in Rust. These are just accidental complexities stemming from unfortunate design decisions in C. Having a richer repertoire of syntactic constructs doesn’t by itself imply such complications.
My point was, replacing n syntactic constructs by n functions or macros doesn’t reduce the cognitive load of having to know how each construct works. To the contrary, one can argue that everything having the same syntactic form makes it more difficult to distinguish different classes of features.
> The first one is pretty C-specific and for example doesn’t exist in Java.
It was just an example, most languages have quirks like this. I don’t know about Java, but in Rust you have the turbofish operator, whose necessity stems from using the less-than sign as both an operator and a delimiter.
> My point was, replacing n syntactic constructs by n functions or macros doesn’t reduce the cognitive load of having to know each of them.
The difference is that if you don’t know a function/macro, you can just read its documentation. If you don’t know a syntactic construct, where do you look?
Another advantage is that if you want to create new functionality similar to existing language features, it won’t stick out like a sore thumb. For example, you could create an until loop:
(until (window-should-close)
(draw-screen))
# is equivalent to
(while (not (window-should-close))
(draw-screen))
In Rust, it would have to look completely different from a while loop:
until!(window_should_close(),
draw_screen());
// is equivalent to
while window_should_close() {
draw_screen();
}