[OpenSCAD] eval( ) ???

Yona Appletree hypher at gmail.com
Sat May 16 20:52:03 EDT 2015


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
>
>
> doug moen <mailto:doug at moens.org>
> May 16, 2015 at 09:44
> Carsten said:
> Personally, I use modules in OpenSCAD extensively, but I would be even 
> happier with a class concept with both member functions and data 
> members. A 3d hierarchy can be expressed also that way.
> ... Perhaps one could keep the OpenSCAD language limited and use it as 
> an intermediate representation generated by the kind of object 
> oriented language I am dreaming of :-)
>
> The OpenSCAD2 design that I am working on will have a very simple 
> object model. Consider a typical OpenSCAD script: it has some named 
> numeric parameters at the top, then some function and module 
> definitions, then some top level geometry statements that render the 
> model based on the parameters. So that's an object. An object is a set 
> of top level definitions (name/value pairs), plus a list of values 
> (which are normally geometric shapes). OpenSCAD2 has a syntax for 
> referencing an external library file as an object, and a syntax for 
> object literals (just an OpenSCAD script, surrounded by braces). Given 
> an object, you can reference its named components using dot notation 
> (object.name <http://object.name>), or you can reference the object in 
> a geometric context (as an argument to a geometric transformation, or 
> at the top level of a script), in which case the object behaves like 
> its geometry.
>
> There are a few more details, but that's the basic idea. Note that 
> this is much simpler than object oriented programming. There are no 
> mutable objects, no classes or user defined types, no support for 
> encapsulation or data abstraction. But, as I mentioned, objects do 
> have "member functions and data members", so it may go part way 
> towards satisfying Carsten's requirements. Objects will also satisfy 
> Runsun's requirement for associative arrays. I also think that 
> constructing a 3D model as a tree of objects will give us a better 
> (more declarative) way to support bill-of-materials.
>
> We want to preserve the simple and declarative nature of OpenSCAD. I 
> believe that this very simple object model will address some of the 
> main pain points in doing geometric modelling with OpenSCAD, without 
> turning it into a complex OOP language.
>
>
> _______________________________________________
> 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 14, 2015 at 09:58
> Hi Marius!
>
> On 2015-05-14 16:22, Marius Kintel wrote:
>> OpenSCAD aim to directly describe a 3D design hierarchy, not merely
>> execute code to spit out 3D objects.
>
> I do understand, and any language chosen would obviously have to 
> support the design hierarchy. As far as I can tell, many languages 
> should be able to do it. Personally, I use modules in OpenSCAD 
> extensively, but I would be even happier with a class concept with 
> both member functions and data members. A 3d hierarchy can be 
> expressed also that way.
>
> Anyway, this was just my thoughts. OpenSCAD has made decisions long 
> ago, which I respect. Perhaps one could keep the OpenSCAD language 
> limited and use it as an intermediate representation generated by the 
> kind of object oriented language I am dreaming of :-)
>
>> Using a faster and more powerful CAD kernel is indeed on the radar.
> > Sadly, the world of Open Source CAD kernels is severely limited.
>> If we manage to get sufficient contributions or funding, working
> > towards such a kernel would be doable. If you have any spare
> > time, this would be a good place to start:
>> https://github.com/openscad/openscad/wiki/Project%3A-Survey-of-CSG-algorithms 
>>
>>
>> ..or if someone has the experience to do so: Evaluate OpenCascade as an
>> option. Most people I've talked to who've ever used that has strongly
>> recommended me never to touch it though. ..but FreeCAD somehow manages.
>
> The funny thing is, I evaluated CAS.CADE (as it was known at the time) 
> in about 1994-1995 for the work previously mentioned. It was marketed 
> by Matra Datavision in France and I even went to see them a couple of 
> times. They had what we thought was a curious idea of their own 
> home-grown language (CDL) encapsulating the C++ kernel. Nowadays it 
> looks like some finally agree with our thoughts at the time :
> http://dev.opencascade.org/doc/overview/html/occt_dev_guides__cdl.html
>
> "Please note that CDL is considered as obsolete and is to be removed 
> in one of future releases of OCCT."   :-)
>
> CAS.CADE was closed source and extremely expensive back then, but we 
> still struggled very hard to make use of it. The end result for us was 
> that it was dropped and replaced it with ACIS. Only a few years ago, I 
> discovered CAS.CADE had become quasi open source as OpenCascade 
> (OCCT). I also found there is now something called OCE - Open CASCADE 
> Community Edition https://github.com/tpaviot/oce/
> I had the idea of trying OCE, but frankly not enough incentive and 
> power to do it, and my work is different now. OCE may probably be 
> something to be considered for OpenSCAD CAD kernel, I suspect 
> OpenCascade has come a long way since I saw it.
>
> Sidenote: One thing that has struck me is that the compilation in 
> OpenSCAD is quite fast, but the rendering (F6) is extremely slow. I 
> was wondering if the generation of triangles for STL really needs the 
> graphical rendering to be completed first? If not, one could imagine a 
> function to export the compiled model to STL and use an external 
> viewer to speed things up when iterating on a complex design that 
> takes forever to render.
>
> Carsten Arnholm
>
>
>
> _______________________________________________
> OpenSCAD mailing list
> Discuss at lists.openscad.org
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openscad.org/pipermail/discuss_lists.openscad.org/attachments/20150516/dc844f20/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/20150516/dc844f20/attachment.jpg>


More information about the Discuss mailing list