[OpenSCAD] Proposal for extensions to the OpenSCAD syntax

Hugo Jackson hugo at apres.net
Mon Oct 28 00:24:28 EDT 2019



> On Oct 27, 2019, at 5:13 PM, Torsten Paul <Torsten.Paul at gmx.de> wrote:
> 
> First note that the function literals are now
> implemented, so the snapshot version of OpenSCAD
> has functions as first class values which means
> support for higher order functions.
> (https://github.com/openscad/openscad/pull/3077)
> 
> I hope to find some time to collect notes and post
> an article about it. Meanwhile the minimalist docu
> can be found at
> https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/User-Defined_Functions_and_Modules#Function_Literals
> 
> On 28.10.19 00:09, Hugo Jackson wrote:
>> To start, I would propose an extension of the "dot"
>> notation, that would allow one to refer to a value
>> declaration and/or function or module component of
>> another module with a dot.
> 
> Yes, having access to a nested data structure is
> definitely something that would help a lot. The
> core changes to the parser implementation that are
> required for this are now done and merged to the
> development snapshot.
> 
> But I don't think it will be possible to link to
> the existing function and/or module definitions.
> 
> Slightly modified example, just adding a parameter
> to module foo():
> 
> module foo(offset) {
> 	valueA = 7 + offset;
> 
> 	function myFunc(num) = valueA + num;
> }
> 
> module bar() {
> 	valueB = 8;
> 
> 	valueC = foo.valueA + foo.myFunc(valueB);
> }
> 
> foo(10);
> translate([10, 10, 0]) foo(20);
> 
> bar(); // <- now what is valueC ?
> 

Good point… for my part I don’t usually code modules with parameters, but I appreciate that isn’t how the real world works. :)
But I would think that calling any module part or function would require an enumeration of all needed values in the parameter arguments, e.g. for the example you
provide the call for valueC in bar would need to be:

valueC = foo(offset = 7).valueA + foo(offset = 7).myFunc(valueB) … or literally valueC = foo(7).valueA + foot(7).myFunc(valueB)

Perhaps that would lead to a preponderance of code that would only serve to make code look more tortuous than it already does. Yet I think the
proposed ‘dot’ syntax would lead to more insightful coding that would tend to mitigate the damage that might occur. 

> 
>> The second extension would be the election of three
>> operations as 'reserved' functions, union, difference
>> and intersection such that one could explicitly call
>> that part of a module without calling the others:
> 
> I'm not sure I understand how this will work. Why
> select specifically those 3 special cases?
> 
> Is that meant just as names or would that also mean
> intersection() { bar(); foo(); } a bit like operator
> overloading?
> 
>> foo(); // would execute intersection(){difference(){union(){<union code>}<difference code>}<intersection code>}
> 
> Where's the nesting coming from? From the order of
> the definitions?
> 
>> Please let me know… I didn’t want to bog this
>> proposal down with details if it’s obvious, but in
>> doing that I have taken the risk that the improvement
>> And benefits of such extensions may not be evident.



I often code modules using a special varialble I name $e and a skeleton module that looks like this:

module foo($e = -1) {
	module _union() {
		// code that primarily builds the object
	}

	module _diff() {
		// code that primarily subtracts geometry from _union()
	}

	difference() {
		if($e == -1 || $e == 0)
			_union();
		if($e == -1 || $e == 1)
			_diff();
	}		
}

I then get to call foo and either get just the _union code or just the _diff code or have the object definition run completely when $e == -1

With this approach, when I just want the foo object I simply write:

foo();

But if I want the foo object to be united with some other objects before any difference is applied I could do it like this:

module bar() {
	difference() {
		union() {
			foo($e = 0);
			cylinder(d = 5, h = 10);
		}
		foo($e = 1);
	}
}

I find that this kind of approach helps with the overall flow and data abstraction, but the addition of a special variable and the requirement for the difference(){union() {}} code to make it work detracts from what I feel is overall a more elegant approach, and I find it particularly helpful for code reuse.
So that’s really what my suggestion for ’reserved’ functions is about.. following the logic that you would execute union functionality before difference because you need to have first constructed an object before you remove anything from it. Don’t almost all modules have the…

difference() {
	union() {
		// add some stuff
	}
	// take some stuff away
}

construct in them?

So that’s why I was thinking that a syntax that supported what I have at least found to be the most common code construction would make code more readable, so that I would just write:

module foo() {

	union : {
		// code that primarily builds the object
	}
	diff : {
		// code that primarily subtracts geometry from union()
	}

	// code that follows executes only if foo is called
}

Now when I want the foo object to be combined with other objects, I would just have to write:

module bar() {
	union : {
		foo.union();
		_cylinder(d = 5, h = 10);
	}
	diff : {
		foo.diff();
	}
} 

Perhaps there may be a more elegant way of structuring things, but I was aiming at a syntax that while not backwards compatible, wouldn’t break anything that was already working.

Thanks for the heads up on the availability of function literals… that should make life more fun and exciting. And thanks for the links to the discussion lists.





More information about the Discuss mailing list