doug-moen / openscad2

better abstraction mechanisms for OpenSCAD
Boost Software License 1.0
25 stars 3 forks source link

Pipeline notation #17

Closed Neon22 closed 9 years ago

Neon22 commented 9 years ago

IMHO this issue of whether a call is stacked or not - is key to readability in current OpenSCAD programs. The syntactic sugar around the problem is annoying to some and essential to others. The reader has to know hidden knowledge. E.g. Twist() you refer to in several places as an example. The code would behave very differently if it was a user function that returned a number). (aside - can users overwrite predefined functions ?)

The existing solution requires careful searching for {} and ; closers. It also requires absolute knowedge of all the functions to know if a module references children or not. There is no clue in the syntax. E.g. cube() vs rotate() So this pipeline is currently legal:

scale([0.5,1,1.5])
  rotate([45,45,45])
    translate([10,20,30])
      cube(10)

and so (I think) is this:

scale([0.5,1,1.5]) {
  rotate([45,45,45]) {
    translate([10,20,30]) {
      cube(10)
}}}

The use of the existing block {} is just as clear and does not add syntactic sugar '>>' to the language. Some languages have gone to extreme lengths to remove syntactic sugar. E.g. Python would enforce indentation and remove all {}; but I'm not suggesting that.

IMHO making it optional (like ; inside the last } is not very helpful. It makes it easy for people to type one less character but sacrifices clarity. But then I'm a LISP guy so as long as my IDE supports highlighting matching braces and allows block indenting - I'm happy.

My vote would be to not add another layer of sugar to the syntax but instead try to pare it away...

doug-moen commented 9 years ago

The purpose of pipeline notation in OpenSCAD is to eliminate the need to write nested module calls where lots of }}} pile up at the end of the statement. If you look at existing OpenSCAD code, you'll see that most people prefer to use pipeline syntax wherever possible, and that the alternative syntax of nested module calls is used much less frequently.

When talking to Marius Kintel, the leader of the OpenSCAD project, I received a clear message that pipeline syntax is a valuable part of the language that needs to be preserved.

I'm proposing to generalize pipeline notation by adding an explicit << operator to both the statement and the expression syntax. This has two benefits.

  1. It will allow pipeline syntax to be used in expressions in contexts where it would otherwise be disallowed. In an expression, the original "implicit" pipeline syntax doesn't work if the child argument contains operators.
  2. It makes pipelines easier to read when they extend over multiple lines.

Your argument is that, as a Lisp programmer, you are used to writing expressions containing deeply nested function calls, with lots of ))) piling up at the end of a complex expression. And this doesn't bother you, because your IDE takes care of this for you. So I think you are arguing that OpenSCAD's existing pipeline notation can simply be eliminated, and that people should just get used writing nested module calls with lots of }}} at the end of the statement. This is what I think you mean by your vote to "pare away" syntax. My proposal is to generalize pipeline notation, and you think it is better to simply get rid of it.

I understand where you are coming from. I use Scheme myself, and I'm not troubled by the syntax.

However, I think that any attempt to persuade the OpenSCAD community to embrace a more Lisp-like syntax is doomed to failure. It would certainly be simpler to deprecate pipeline syntax, supporting it in statements for backwards compatibility, but not supporting it in expressions at all. However, my sense is that this would not be acceptable to most of the community.

Also, I've noticed that most functional languages have an explicit pipeline operator. When a functional language has first class functions, then certain idioms become possible that are clearer and easier to write when you have pipeline syntax. OpenSCAD2 extends OpenSCAD with first class functions, and those same functional idioms are also useful in OpenSCAD, so generalized pipeline syntax makes sense for our language.

Finally, there is an objective reason why Lisp syntax has consistently failed to get much traction in the programming world. The reason is infix operators. Historically, it was the introduction of mathematical notation, writing "x + y" instead of "the sum of x and y", that made modern mathematics possible. Once you have infix operators, it becomes possible to write complex mathematical expressions and reason about them. It comes possible to notice that + is a commutative operator (x + y == y + x), that + is associative, and then you can proceed to find more complex patterns, like De Morgan's law. These laws are not easy to discover or understand if you don't first have infix operators. The pipeline operator is an infix operator that makes the logic of pipelines easier to read and understand than if you write them as nested function calls.

Neon22 commented 9 years ago

You've obviously carefully considered your approach. Sounds good.