[OpenSCAD] eval( ) ???

Yona Appletree hypher at gmail.com
Mon May 18 02:01:28 EDT 2015


Doug,

I am also interested in any design documents or grammars you have for 
OpenSCAD2 -- it's quite an undertaking to bring these new concepts to 
the language, thanks for your effort.

Like you said, I think we're on the same page, mostly. The main 
difference is that it sounds like you're thinking of OpenSCAD files as 
the class-like thing, whereas I imagined modules/functions to be fairly 
easily extensible into class-like objects. In the end, it doesn't matter 
much.

If there is a public discussion forum about these ideas, I would enjoy 
participating in the discussion, exploring specific use cases, etc... 
This thread seems a bit overcrowded for that discussion, however.

- Yona

> doug moen <mailto:doug at moens.org>
> May 16, 2015 at 19:27
> Hi Yona. I find parts of your post confusing (the term "module" is 
> overloaded), but we are thinking along the same lines.
>
> A quick way to summarize my thinking is that you don't need classes to 
> do object oriented programming. The prototype/delegation paradigm used 
> by Javascript is just as powerful. But if all objects are immutable, 
> then you don't need delegation, and things get really simple. You just 
> need:
>
>  1. object literals
>  2. a way to make a new object by specifying the differences from an
>     old object. Or: a way to customize an object, overriding some
>     fields, resulting in a new object.
>  3. functions
>
> And that's it, you have a functional OOP system. It's simple, more 
> powerful than it looks, and good enough for our purposes.
>
> OpenSCAD already has the above 3 concepts:
>
>  1. an OpenSCAD script corresponds to an object
>  2. you can customize a script, overriding some definitions, by
>     writing 'include <scriptname>' and then writing new definitions
>     that override some of the bindings inherited from <scriptname>.
>     Or, you can override definitions within a script from the command
>     line using the -D flag.
>  3. OpenSCAD has functions. Also, 'module' definitions are really just
>     functions by another name.
>
> OpenSCAD 2 just generalizes these already-existing concepts. It adds 
> object literals and first class object values. It adds a better syntax 
> for customizing an object. It unifies "functions" and "modules", using 
> the word "function" to describe both.
>
> Now I'll copy and paste part of Yona's post, with terminology and 
> syntax changed to correspond to my current OpenSCAD 2 design:
>
>
> Doug Moen.
>
>
> _______________________________________________
> OpenSCAD mailing list
> Discuss at lists.openscad.org
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
> Yona Appletree <mailto:hypher at gmail.com>
> May 16, 2015 at 17:52
> Doug,
>
> This is a fascinating discussion, and I wanted to chime in about 
> objects and mutability (full disclosure, experienced programmer). I 
> have an interest in functional, immutable programming styles, but have 
> not personally used lisp or Haskell. Most of my experience is with Scala.
>
> I think you can preserve much of the usefulness of objects while 
> keeping a simple syntax and immutability. In fact, we don't even 
> really need a new keyword. Modules are fine as is, with a few minor 
> extensions. The main features that seem useful are:
>
>  1. Combining data, geometry and functions into one variable space
>  2. Module mix-ins
>  3. Access to module parameters and variables as "fields"
>  4. A module "copy" method. I will use the name "with", where you can
>     specify overrides to the parameters and variables in the modules.
>     This would return a copy of the module with the new values,
>     keeping immutability.
>
> Carsten's example would look something like this:
> module Lollipop(
> radius,
> diameter,
> height
> ) extends Geometry /* This could be the default, and not needed to be 
> stated explicitly */ {
> translate([0,0,height]) sphere(r=radius);
> cylinder(d=diameter,h=height
> }
>
> // modules exist as before
> module example_model()
> {
> // create 2 lollipops of different sizes, the second dependent on the 
> first
>
> lolA = Lollipop(radius = 10, diameter = 2, height = 50);
> lolB = lolA.with(radius = lolA.radius*2, diameter = lolA.diameter*2); 
> // height is omitted -- it stays the same
>
> // create a cube representing the table plate.
> // cube is a module just like everything else (albeit a native one),
> // and it's parameters ARE accessible, and has a .with() if needed.
> table_plate = cube(size=[100,100,5], center=true);
>
> // union, a member of the base geometry module, returns an immutable 
> copy of itself
> // unioned with the arguments to union. Since we are a module, any 
> geometry declared is
> // implicitly unioned as before.
> table_plate.union(lolA, lolB);
> }
>
> // construct the exmple model and export it as STL
> example_model()
> .render() // Produces rendered geometry... more on this later
> .exportStl("lollipops_on_table.stl"); // magic strings are ugly. Use 
> an actual method name for STL
>
> But these extensions would allow far more, but remain mostly, if not 
> completely backwards compatible. We can actually implement the 
> "geometry" base module using the existing functionality of OpenSCAD:
> module GeometryBase {
> unionOf = (args* /*vararg syntax tdb, of course */) -> { /* Anonymous 
> function syntax TDB */
> union() {
> this
> args
> }
> }
>
> rendered = (x = 1) -> render(x) { this }
> }
>
> If we consider { ... } to be an "inline module", you get associative 
> arrays for free:
>
> data = {
>     a = 10;
>     b = 20;
> }
> echo(data.a); // Valid because variables of modules are exposed
>
> // You can create a copy with new values as well
> data2 = data.with(b=30, c=100);
>
> Just my two cents, but it would be a simple way to keep backwards 
> compatibility and all the desirable current features while giving the 
> programmers many of the features that feel natural to us.
>
> - Yona
> doug moen <mailto:doug at moens.org>
> May 16, 2015 at 16:35
> Hi Carsten.
>
> One of my top goals for "OpenSCAD 2" is to stay true to the goals and
> philosophy of OpenSCAD. I've tried to figure out what these are by
> talking to Marius and reading forum posts for the last few years.
>
> Some OpenSCAD users are computer programmers like you and me, but many
> are not. If OpenSCAD is your first experience with computer
> programming, then how many new concepts do you need to learn before
> you can be productive? OpenSCAD seems to have a low barrier to entry,
> and we want to keep it this way.
>
> One philosophical principle I've learned from the community is that
> OpenSCAD is intended to be a purely declarative or 'functional'
> language, except that it should also be much easier to learn than
> serious functional languages such as Haskell. This means that there is
> no state. You can't increment a variable or modify a data structure
> in-place.
>
> Traditional OOP languages are based on the idea of objects with state,
> and there is a lot of additional heavy weight machinery that you need
> to learn before you can be productive. But we don't want this: we'll
> end up with a language that is easy to use once you have learned
> object oriented programming, but it with a higher barrier to entry for
> beginners.
>
> In your first example (class lollipop), you defined a class, you
> defined a constructor inside the class, you declared data members then
> separately assigned them initial values within the constructor, and
> you have an assignment to the special variable 'this'. You used a lot
> of machinery to accomplish something very simple.
>
> In your second example (module example_module), you create a mutable
> object and modify its state, in these lines:
>>      table_plate = cube(size=[100,100,5],center=true);
>>
>>      // union the lollipops with the table plate and return it
>>      table_plate.union(lolA);
>>      table_plate.union(lolB);
>>
>>      // be explicit about what the module returns
>>      return table_plate;
> But we want OpenSCAD to be purely declarative, without state mutation semantics.
>
> When I have more time, maybe I'll try and rewrite your code in
> OpenSCAD 2, to demonstrate that the same things can be accomplished in
> a simpler way, without all the heavy machinery of OOP.
>
> Doug Moen.
>
> On 16/05/2015, Carsten Arnholm<arnholm at arnholm.org>  wrote:
>> On 2015-05-16 19:33, G. Wade Johnson wrote:
>>> Is there a {beta,alpha,prototype} version of OpenSCAD2 somewhere for
>>> people to play with? Is there a spec to read?
>>>
>>> I, for one, would like to see anything you are willing to share on this.
>> That was my reaction as well.
>>
>> In my opinion, classes are not there to complicate things. On the
>> contrary, it is an important tool for simplification. Being able to name
>> a type, encapsulate its data members and provide member functions would
>> go a long way towards the goal of being more expressive without
>> complicating things.
>>
>> In my line of thinking, which may be different from OpenSCAD2 (as I have
>> not grasped the full idea of it), the main ideas would be:
>>
>> classes would be used for constructing named parametric objects
>> (instantiation) and being able to union, intersect and difference the
>> result with other named or unnamed objects (union(), intersect() and
>> difference() would be member functions on any class. unlike a module, a
>> class may contain data members unique to each instance created.
>>
>> Below is just a silly example to illustrate: 2 lollipops on a table.
>> The difference between a module and a class here is that a class may be
>> instantiated and may remember its construction parameters so they can be
>> re-used later. It also owns its CSG object.
>>
>> // classes are new
>> class lollipop {
>>
>>      // a constructor is a member function with the same name as the class
>>      lollipop(rad, diam, hei)
>>      {
>>         // keep data members
>>         radius   = rad;
>>         diameter = diam;
>>         height   = hei;
>>
>>         // "this CSG object"
>>         this = union() {
>>            translate([0,0,height]) sphere(r=radius);
>>            cylinder(d=diameter,h=height);
>>         };
>>      }
>>
>>      // data members of the class
>>      radius;
>>      diameter;
>>      height;
>> };
>>
>>
>> // modules exist as before
>> module example_model()
>> {
>>      // create 2 lollipops of different sizes
>>      // the second is dependent on the first
>>
>>      lolA = lollipop(rad=10,diam=2,hei=50);
>>      lolB = lollipop(lolA.radius*2,lolA.diameter*3,lolA.height);
>>
>>      // create a cube representing the table plate. Here,
>>      // the construction parameters cannot be accessed later
>>      // since the cube is a primitive only
>>      table_plate = cube(size=[100,100,5],center=true);
>>
>>      // union the lollipops with the table plate and return it
>>      table_plate.union(lolA);
>>      table_plate.union(lolB);
>>
>>      // be explicit about what the module returns
>>      return table_plate;
>> }
>>
>> // construct the exmple model and export it as STL
>> example_model().render().export("STL","lollipops_on_table.stl");
>>
>>
>> You could go on, classes could have data members being instantiations of
>> other classes, or even containers containing such.
>>
>> The above is just meant as a supplement to what I wrote before,
>> illustrating the idea that the OpenSCAD language could be extended in a
>> direction which would be immediately recognisable to programmers, while
>> still being backwards compatible with existing OpenSCAD code. If you
>> want to express things as it is currently being done, you can, but you
>> also have other possibilities.
>>
>> Again, just my thoughts. I don't know if it would be easy to implement.
>>
>>
>> Carsten
>>
>>
>> _______________________________________________
>> OpenSCAD mailing list
>> Discuss at lists.openscad.org
>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>>
>>
>
> _______________________________________________
> OpenSCAD mailing list
> Discuss at lists.openscad.org
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
> Carsten Arnholm <mailto:arnholm at arnholm.org>
> May 16, 2015 at 15:08
>
>
> That was my reaction as well.
>
> In my opinion, classes are not there to complicate things. On the 
> contrary, it is an important tool for simplification. Being able to 
> name a type, encapsulate its data members and provide member functions 
> would go a long way towards the goal of being more expressive without 
> complicating things.
>
> In my line of thinking, which may be different from OpenSCAD2 (as I 
> have not grasped the full idea of it), the main ideas would be:
>
> classes would be used for constructing named parametric objects 
> (instantiation) and being able to union, intersect and difference the 
> result with other named or unnamed objects (union(), intersect() and 
> difference() would be member functions on any class. unlike a module, 
> a class may contain data members unique to each instance created.
>
> Below is just a silly example to illustrate: 2 lollipops on a table.
> The difference between a module and a class here is that a class may 
> be instantiated and may remember its construction parameters so they 
> can be re-used later. It also owns its CSG object.
>
> // classes are new
> class lollipop {
>
>    // a constructor is a member function with the same name as the class
>    lollipop(rad, diam, hei)
>    {
>       // keep data members
>       radius   = rad;
>       diameter = diam;
>       height   = hei;
>
>       // "this CSG object"
>       this = union() {
>          translate([0,0,height]) sphere(r=radius);
>          cylinder(d=diameter,h=height);
>       };
>    }
>
>    // data members of the class
>    radius;
>    diameter;
>    height;
> };
>
>
> // modules exist as before
> module example_model()
> {
>    // create 2 lollipops of different sizes
>    // the second is dependent on the first
>
>    lolA = lollipop(rad=10,diam=2,hei=50);
>    lolB = lollipop(lolA.radius*2,lolA.diameter*3,lolA.height);
>
>    // create a cube representing the table plate. Here,
>    // the construction parameters cannot be accessed later
>    // since the cube is a primitive only
>    table_plate = cube(size=[100,100,5],center=true);
>
>    // union the lollipops with the table plate and return it
>    table_plate.union(lolA);
>    table_plate.union(lolB);
>
>    // be explicit about what the module returns
>    return table_plate;
> }
>
> // construct the exmple model and export it as STL
> example_model().render().export("STL","lollipops_on_table.stl");
>
>
> You could go on, classes could have data members being instantiations 
> of other classes, or even containers containing such.
>
> The above is just meant as a supplement to what I wrote before, 
> illustrating the idea that the OpenSCAD language could be extended in 
> a direction which would be immediately recognisable to programmers, 
> while still being backwards compatible with existing OpenSCAD code. If 
> you want to express things as it is currently being done, you can, but 
> you also have other possibilities.
>
> Again, just my thoughts. I don't know if it would be easy to implement.
>
>
> Carsten
>
>
> _______________________________________________
> OpenSCAD mailing list
> Discuss at lists.openscad.org
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
> G. Wade Johnson <mailto:gwadej at anomaly.org>
> May 16, 2015 at 10:33
> Is there a {beta,alpha,prototype} version of OpenSCAD2 somewhere for
> people to play with? Is there a spec to read?
>
> I, for one, would like to see anything you are willing to share on this.
>
> G. Wade
>
> On Sat, 16 May 2015 12:44:38 -0400
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openscad.org/pipermail/discuss_lists.openscad.org/attachments/20150517/eba0eb9f/attachment-0002.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: compose-unknown-contact.jpg
Type: image/jpeg
Size: 770 bytes
Desc: not available
URL: <http://lists.openscad.org/pipermail/discuss_lists.openscad.org/attachments/20150517/eba0eb9f/attachment.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: postbox-contact.jpg
Type: image/jpeg
Size: 1152 bytes
Desc: not available
URL: <http://lists.openscad.org/pipermail/discuss_lists.openscad.org/attachments/20150517/eba0eb9f/attachment-0001.jpg>


More information about the Discuss mailing list