upvote
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.
reply
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?
reply
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.

reply
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!
reply
That just moves the subtle and often arbitrary differences to the functions and macros you use.
reply
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?
reply
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.

reply
> 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();
  }
reply