Skip to content

File Format Versioning

Michael edited this page May 20, 2014 · 12 revisions

Sometimes, it's necessary to break backwards compatibility to be able to provide improvements to OpenSCAD. We'll discuss ways of doing this, as well as enumerate some of the suggested breaking changes.

Versioning

One way of versioning OpenSCAD files is to add a version tag, similar to e.g. GLSL or VRML

#openscad 2014.03

union() {
  cube(); 
  sphere();
}

This enables us to detect for which version of OpenSCAD a design was intended.

When creating new files with the built-in editor, we could automatically add a missing tag. When opening a file without a tag, we could issue a warning

Existing OpenSCAD designs shouldn't suffer from changes in the language. To handle old designs, we could

  • Issue a warning and have people use an old version of OpenSCAD
  • Offer to upgrade existing designs
  • Have two built-in renderers and give users an option to use the old one

Alternatively, could have a 'base' version on preferences which is added to a new file, and used implicitly as the base for opened files missing a version spec (rather than adding text to an opened file - don't want to do changes to existing files). That way a user can work with a fixed version (of the language) while using updates (for bug fixes etc) without having to transition to the next language version/features etc, until they are ready.

Language changes

Implicit Unions

See OEP2:-Implicit-Unions

Namespaces

See https://github.com/openscad/openscad/issues/522

As a sub section: Consider unification of variable, function and module namespaces.

General module name and parameter cleanup

The naming scheme and default values of the built-in OpenSCAD modules are not quite orthogonal and coherent. We should consider cleaning these up when doing a non-compatible language change. Examples:

  • linear_extrude takes a height parameter, while cylinder takes h
  • sphere is centered around the origin while cube and cylinder is not.

We should consider making argument lists a bit stricter with positional arguments too. For example, not allowing positional arguments located after named ones.

Assignment Semantics

Started by Oskar on the mailing list:

The sequential assignment semantics of the proposed let() should ideally be aligned with the future idea of having scoped variables, and I am interested in what the intention is here. The current behavior is (as has been discussed before) not ideal, and there may be a few different options of how to change that. Considering the following two cases (and their current behavior in the comment)

a=1; b=a; a=2;  // b == 2
d=c; c=2; // WARNING: Ignoring unknown variable 'c', d == undef

The options I see are:

  1. Introduce sequential assignment with reassignment. This will silently change b to 1 in the example above, which will cause silent breakage.

  2. Introduce sequential assignment without allowing reassignment (i.e. make it an error). This will probably break some few cases of existing code, but not silently and with an easy way to fix.

  3. Introduce recursive assignment disallowing reassignment. -> This will change d to 2 in the example above which theoretically could silently break some existing code, but quite unlikely.

  4. Of course: Do nothing.

So: 1 -> silent breakage. 2 -> less breakage but not silent. 3 -> low risk of silent breakage. From an implementation point of view, 1 and 2 are quite a bit simpler to implement.

My suggestion would be to do 2, but start with a depreciation warning. That is also in line with the current let-syntax (especially if we disallow reassignment).

The use case of supplying variables on the command line with them just being appended to the current file could be handled in a special way to keep that support.

The following case is interesting too:

   i = 1;
   module foo() {
       function f() = i;
       echo(f());
       a = f();
       echo(a);
       i = 2;
       echo(f());
       b = f();
       echo(b);
   }
   foo();

Before testing, can you guess what it outputs? Should module calls be interleaved with expression evaluation?