The Looseleaf Papers

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.

Languages design issues

No error handling

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.

http://forum.openscad.org/Would-be-nice-to-have-constraints-assertions-on-functions-modules-td11237.html

Feature request for assert:

https://github.com/openscad/openscad/issues/381

Silent value replacement

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.

No 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.

No vector index bounds checking

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

https://github.com/openscad/openscad/issues/1574

No structs or enums

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

https://github.com/openscad/openscad/issues/1032

No associative arrays

OpenSCAD has no associative arrays or dictionaries.

Use of the search() function can emulate this to some extent, but there is no data structure corresponding to a hash table.

Mandatory semicolons

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:

Cryptic syntax error messages

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.

Summary

OpenSCAD is lacking important usability features such as error handling and namespaces, basic safety features such as warnings for vector index bounds check and variable value overwriting, and lacks data types important for 3D CAD applications such as structs, enums, and associative arrays. Together this makes it difficult to write code in OpenSCAD that is correct and comprehensible, and also makes it difficult to debug when things go wrong.

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/

CAD limitations

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

https://github.com/openscad/openscad/issues/265

Limited import support for other formats

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.

https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/FAQ#I.27m_getting_.22Unsupported_DXF_Entity.22_warnings_when_importing_DXF_files.2C_what_does_that_mean.3F

http://forum.openscad.org/Importing-DXF-td3443.html

Function programming limitations

I would also argue that OpenSCAD’s commitment to a functional programming style is debatable. Here’s why:

No arity checking

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.

No higher-order functions

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.

No referential transparency

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.

https://news.ycombinator.com/item?id=22527535