OpenSCAD is not a good programming language
Created
Modified
Published
OpenSCAD is a wrapper around OpenCSG, a constructive solid geometry library. It works reasonably well for producing STL files from geometric primitives.
But the documentation also makes it sound as though OpenSCAD is a good programming language.
The variable retains its last assigned value at compile time, in line with Functional programming languages. Unlike Imperative languages, such as C, OpenSCAD is not an iterative language, as such the concept of x = x + 1 is not valid, get to understand this concept and you will understand the beauty of OpenSCAD.
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#Variables
I posit that OpenSCAD is a bad programming language, and is bad in ways that make it harder to use for CAD. Specifically:
OpenSCAD has no user-defined error-handling such as exceptions or assertions.
There isn’t even an exit() function.
Not for lack of trying, though.
Feature request for assert:
OpenSCAD assigns variable values at compile-time, but does not warn if they are overwritten.
This means that later assignments will silently overwrite previous values for the entire scope. For example, this code:
a = 1; echo(a); a = 2; echo(a); a = 3; echo(a);
will yield this output:
ECHO: 3 ECHO: 3 ECHO: 3
which is surprising behavior for a language that uses C-like procedural syntax and is otherwise evaluated top-to-bottom.
In other words OpenSCAD variables are more like constants, but with an important difference. If variables are assigned a value multiple times, only the last assigned value is used in all places in the code.
[ … ]
This behavior is due to the need to supply variable input on the command line, via the use of -D variable=value option. OpenSCAD currently places that assignment at the end of the source code, and thus must allow a variables value to be changed for this purpose.
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/General#Variables
This is touted as a feature.
While this appears to be counter-intuitive, it allows you to do some interesting things: For instance, if you set up your shared library files to have default values defined as variables at their root level, when you include that file in your own code, you can ‘re-define’ or override those constants by simply assigning a new value to them.
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/General#Scope_of_variables
Interesting is not the same as desirable.
There are other ways to handle this. For example, gnuplot allows overriding values from the command line, but does not use the same “last one wins” assignment model.
https://stackoverflow.com/questions/12328603/how-to-pass-command-line-argument-to-gnuplot
GNU make has an entire page on how to override variables.
https://www.gnu.org/software/make/manual/html_node/Overriding.html
This is a situation where “explicit is better than implicit”, since it is all too easy accidentally override them, which brings up the issue of namespaces.
OpenSCAD has no namespaces.
The include statement does not make a new namespace. Instead, it
acts as if the contents of the included file were written in the including file
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Include_Statement
This includes re-defining any global variables present in the included file, again with the “last assignment overrides any other values” rule.
OpenSCAD has no vector index bounds checking.
For example, it will happily compile this:
cube([2.1, 3.1, 4,1]);
as this:
cube([2.1, 3.1, 4]);
without so much as a warning.
Similarly, these assignments:
a = [1, 2, 3]; b = a[3]; c = a[-1]; echo(a); echo(b); echo(c);
will result in:
ECHO: [1, 2, 3] ECHO: undef ECHO: undef
instead of warning of a bounds violation.
OpenSCAD doesn’t report errors, it silently ignores them. Good luck if you need to debug something.
—Doug Moen
OpenSCAD lacks structs and enums.
When working with 3D solids, structs would be useful for this sort of thing:
diode.d = 9.10; diode.h = 6.04; diode.xyz = [24.48, 26.78, -0.6]; translate(diode.xyz) cylinder(h=diode.h, d=diode.d, $fn=50);Unfortunately, there is no such mechanism in OpenSCAD. The only collection type is a vector, so the only way to access parts of a collection is with numeric indices.
Feature request: Enums / Enumerations #1032
OpenSCAD requires semicolons to terminate statements.
Scripting languages like Python, Ruby, and Lua use the end of line to terminate statements. Semicolons are only necessary when there are multiple statements per line.
OpenSCAD, by contrast, requires semicolons to terminate every statement. If this provided better syntax errors, it might be justifiable. Unfortunately, this is not the case, because:
OpenSCAD’s syntax errors are uninformative.
For example, this code is missing a semicolon on line 1:
a = 1 echo(a);
But OpenSCAD throws this error:
Parser error in line 2: syntax error
and highlights the parenthesis at column 5.
An expression may span multiple lines, so this can make the actual error distant from the highlighted line.
By contrast, attempting to compile this C code:
#include <stdio.h> int main(int argc, char *argv[]) { int a = 1 printf("%d\n", a); return 0; }results in this error from GCC:
err.c: In function ‘main’: err.c:4:2: error: expected ‘,’ or ‘;’ before ‘printf’ printf("%d\n", a); ^This is a trivial example, but is representative of OpenSCAD’s syntax error messages.
OpenSCAD has no associative arrays.
Use of the search() function can emulate this to some extent, but there is no data structure corresponding to a hash table.
And yes, people have forked it because of these sorts of problems:
OpenSCAD2 is a backwards compatible redesign of OpenSCAD. The main goals are expressive power and ease of use.
https://github.com/doug-moen/openscad2/blob/master/rfc/Overview.md
OpenSCAD is a bunch of C++ that makes CSG files, from which STL and similar files can be made. Why didn’t they use an existing embedded language, such as Lua or Guile?
http://emacstragic.net/programmatic-cad-openscad-alternatives/
In addition to being a poor programming language, OpenSCAD has deficiencies as a CAD tool:
Centering cannot be adjusted by origin.
Feature request: allow center= to accept more than a boolean
OpenSCAD does not play nicely with other CAD formats.
OpenSCAD claims to import STL, OFF, and DXF.
In practice, it only correctly imports a narrow subset of those formats, and will frequently throw errors like “Unsupported DXF Entity” or silently do nothing.
I would also argue that OpenSCAD’s commitment to a functional programming style is debatable. Here’s why:
OpenSCAD has no function arity checking.
The number of arguments to a function is not checked, neither in builtin functions and modules nor user-defined ones:
cube(size=5, center=true, h=20); function myfunc(x) = 2*x+1; echo(myfunc(3,4,5));
If this were to support functional constructs such as partial function application or currying, it might make some sense, but OpenSCAD does not support partial function application or currying, so this is just a source of bugs.
OpenSCAD has no callback functions, lambda (anonymous) functions, or other higher-order functions.
https://github.com/openscad/openscad/wiki/OEP3:-Function-Values-and-Variable-Scoping-improvements
These are the sort of language constructs one would expect in a functional programming style.
Special variables violate referential transparency.
Special variables have dynamic scope, so they can be used to avoid explicitly passing a parameter. Many functional programming languages would use currying or closures instead of relying on dynamic scope.
Addendum 2016-10-10:
It provides a power set of primitive shapes and operations, but the language itself leaves a bit to be desired. This isn’t a beat-up-on-SCAD post, but a few of the things that irked me were:
- Strange function application syntax (parameters in parens after the function name with an expression or block following the closing paren)
- Unclear variable binding rules (multiple passes are made over the code and the results of changing a variable may affect things earlier in the code unexpectedly)
- No package/namespace management
- Multiple looping constructs that depend on what you are going to do with the results, not on how you want to loop
http://adereth.github.io/blog/2014/04/09/3d-printing-with-clojure/
Addendum 2020-03-12:
I love OpenSCAD for everything but the language, which is .. so bad that the rant stays corked.