The syntax of a programming language defines (a) valid notational elements for use and (b) rules of their arrangement. By the way, this definition of syntax resembles very much the notion of a protocol. A protocol defines (a) messages and their constituting elements and (b) rules of valid message sequences. In an interactive programming environment (like if you program in Python interactively via the console), you communicate with the programming system according to a protocol; and the protocol is given by the syntax. There is an interesting duality between the notion of a protocol and the notion of syntax.
If you program in Scheme or Lisp, the syntax has a very interesting form: everything you type in in Scheme has to follow the syntactical form of lists. In Scheme and Lisp, lists are notated in the following way:
Lists can be nested: any element in a list can be a list. This is almost everything you need to know, in order to write down syntactically correct List/Scheme programms. All you have to take care about is that the number of left parentheses match the number of right parentheses.
The uniform syntax of Scheme and Lisp has very interesting consequences. First, program transformation is very easy. You just have to transform lists into lists. The way you do program transformation in Scheme and Lisp is via macros. Macros are a powerful tool in Scheme and Lisp. That is, why generative programming is something, Lisp and Scheme programmers are used to since decades. Second, since the uniform syntax of lists does not provide any kind of hint, what is actually meant by a list, what it is used for, we can't rely on the syntax alone. The syntax is, so to speak, too primitive. In order to understand what a list means in terms of programming instructions, we have to introduce a sort of second layer of "syntax". Certain conventions in the use of lists have to be introduced. For example, if a "if" symbol is the very first element in a list, we have an if-expression at hand, which expects at least two and at most three further list elements: the second is the test, the third the so called consequent, the (optional) forth the alternate.
The point here is that this second layer of syntax does not break the first layer of syntax, the notational form of lists. In other words, the syntax of Lisp and Scheme does not shape and structure the notational form of programs beyond the form of lists. This explains, why Lisp and Scheme programs are not so easy to read. Human beings are very sensitive on visual shape and form; it helps us easily recognize a pattern. In Scheme and Lisp, you need to look "through" all the parentheses and train your brain on the "hidden" layer of syntax; and that takes some time. It's also an ability that gets quite easily lost if not trained permanently.
So, there is a benefit and a drawback with uniform syntax: you get a powerful transformation system, but you loose readability of your programs.
By the way, if you want to, you can benefit from the power of a uniform form (I don't like to say "syntax" in this context) in your favorite OO language as well. Program your conceptions as classes (your second layer) and enable object configurations solely via constructors (your first layer, the uniform "syntax"). (In Python, it's the "__init__"-Method.) Instantiation would look something like this:
The result is that you get an Abstract Syntax Tree (AST) for free and that you can do program transformations if you like. It's a cool technique for creating a Domain Specific Language (DSL). It puts you somewhat closer to the power of Lisp and Scheme.
I'm -- of course -- not the first, who describes the problems of uniform syntax. You can, for example, read about it in the book from Peter van Roy and Seif Haridi, "Concepts, Techniques, and Models of Computer Programming", MIT Press, 2004, p. 544f.
If you program in Scheme or Lisp, the syntax has a very interesting form: everything you type in in Scheme has to follow the syntactical form of lists. In Scheme and Lisp, lists are notated in the following way:
(first_element second_element third_element ...)
Lists can be nested: any element in a list can be a list. This is almost everything you need to know, in order to write down syntactically correct List/Scheme programms. All you have to take care about is that the number of left parentheses match the number of right parentheses.
The uniform syntax of Scheme and Lisp has very interesting consequences. First, program transformation is very easy. You just have to transform lists into lists. The way you do program transformation in Scheme and Lisp is via macros. Macros are a powerful tool in Scheme and Lisp. That is, why generative programming is something, Lisp and Scheme programmers are used to since decades. Second, since the uniform syntax of lists does not provide any kind of hint, what is actually meant by a list, what it is used for, we can't rely on the syntax alone. The syntax is, so to speak, too primitive. In order to understand what a list means in terms of programming instructions, we have to introduce a sort of second layer of "syntax". Certain conventions in the use of lists have to be introduced. For example, if a "if" symbol is the very first element in a list, we have an if-expression at hand, which expects at least two and at most three further list elements: the second is the test, the third the so called consequent, the (optional) forth the alternate.
The point here is that this second layer of syntax does not break the first layer of syntax, the notational form of lists. In other words, the syntax of Lisp and Scheme does not shape and structure the notational form of programs beyond the form of lists. This explains, why Lisp and Scheme programs are not so easy to read. Human beings are very sensitive on visual shape and form; it helps us easily recognize a pattern. In Scheme and Lisp, you need to look "through" all the parentheses and train your brain on the "hidden" layer of syntax; and that takes some time. It's also an ability that gets quite easily lost if not trained permanently.
So, there is a benefit and a drawback with uniform syntax: you get a powerful transformation system, but you loose readability of your programs.
By the way, if you want to, you can benefit from the power of a uniform form (I don't like to say "syntax" in this context) in your favorite OO language as well. Program your conceptions as classes (your second layer) and enable object configurations solely via constructors (your first layer, the uniform "syntax"). (In Python, it's the "__init__"-Method.) Instantiation would look something like this:
If(And(Equal(Var("a"),Var("b")),LessThan(3,4)),Print("Hello"))
The result is that you get an Abstract Syntax Tree (AST) for free and that you can do program transformations if you like. It's a cool technique for creating a Domain Specific Language (DSL). It puts you somewhat closer to the power of Lisp and Scheme.
I'm -- of course -- not the first, who describes the problems of uniform syntax. You can, for example, read about it in the book from Peter van Roy and Seif Haridi, "Concepts, Techniques, and Models of Computer Programming", MIT Press, 2004, p. 544f.