doug-moen / openscad2

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

Customization and backwards compatibility #22

Open kintel opened 8 years ago

kintel commented 8 years ago

From the customization section:

"You can't create a dependency between two fields in the new object, such that customizing one field updates the other.".

Note: This is allowed today, since the customized variable is evaluated in place of the original variable. We should define how to deal with that piece of backwards incompatibility, as this is very common.

Example (using the Thingiverse syntax)

    // Adjust some aspect of the design
    user_variable = 23; // [5:30]

    /* [HIDDEN] */
    // Private variables
    someVar = user_variable/2; // Divide by to to make internal calculations easier

    sphere(someVar);
t-paul commented 8 years ago

Does it help for this case when we restrict the customizer only to the top level variables of the main script/object? I guess anything else will not be easy from the GUI side too and the customization logic is a bit special in the way it injects values into the AST. Not sure how a possible later feature with picking and updating from GUI side could be handled though.

kintel commented 8 years ago

Currently, customization variables are simply appended as text to the end of the file. This is the reason why the variable resolution rules are so weird. If we instead were to insert the values directly into the AST, we could get rid of some of that mess. That would make the disallowed feature mentioned above perfectly valid (unless I misunderstood the original document).

kintel commented 8 years ago

See also this new writeup I just started on: https://github.com/openscad/openscad/wiki/Variable-Resolution

t-paul commented 8 years ago

It probably needs revisiting, but the parameter prototype code injects the values into the AST

kintel commented 8 years ago

Right. That's not released yet, so for backwards compatibility I'm referring to how people do customization today using the cmd-line -D flag.

AST injection sounds a bit more proper for this functionality. I guess we'll just change the -D flag implementation to perform AST injection in the future.

t-paul commented 8 years ago

Yep, although that's going to be a long deprecation phase I guess as we would probably need to leave -D as is and introduce a new -S (or whatever that can be called) that only can set variables. The problem with -D right now is that it can inject anything like -Dlinear_extrude() import("file.dxf") - which probably could just be handled using an include just fine.

doug-moen commented 8 years ago

I'll explain why I wrote that.

OpenSCAD2 has first class function values. A function call has the syntax f(x,y,a=z). What are the semantics of function call?

I intend for there to be a compile phase, where we compile the AST into byte codes, followed by an evaluation phase. Since OpenSCAD2 is dynamically typed, we don't know what f is at compile time. f could be an OpenSCAD function, an OpenSCAD module, or (new concept) an OpenSCAD2 object. So the compiler has to assume the worst case scenario, and generate code for f(x) that will work for any kind of function f.

For the OpenSCAD2 design, I decided it would be reasonable to use standard call-by-value semantics for function calls. This means that the arguments are evaluated first, the resulting values are pushed onto the stack, and then we jump into the compiled function code. This is the industry standard implementation of function calls, and it's efficient. But it doesn't match how OpenSCAD module calls currently work.

The children arguments of a module call are currently evaluated using call-by-name, which means that the unevaluated code is passed as the argument, and the argument code is evaluated each time it is referenced using children(). In a purely declarative language, you can't tell the difference between call-by-value and call-by-name, but in OpenSCAD, you can tell if you use echo or rands, and there is also the weird use of special variables by relativity.scad. So there is a small amount of existing code that will break if modules use call-by-value, but my plan is to offer alternative ways of writing that code.

Now for the case of object customization. If we consider 'object customization' in the general case (not just what's covered by that section), then there is customization within an OpenSCAD script, there is the -D flag, and there is the GUI customizer, where an object is being customized multiple times per second as you drag a slider to adjust a value. The GUI customizer case suggests there is a need for fast, by-value customization, where the argument is a value, not an expression with dependencies. The case of includeing a script, then overriding some of the variable definitions, suggests there is also a need for a slower and more expressive customization mechanism, -- expression override instead of value override -- more akin to overriding a virtual function in a class, where the overridden definition contains an expression that can depend on other definitions in the object.

For the -D flag, I guess this needs to be expression override, not value override.

For the proposed syntax where you can call an object using function call notation, this needs to be value override, in order for function calls to be compiled using the efficient call-by-value mechanism.