I agree that OpenSCAD is frustrating to use for large projects, for people who are used to using a general purpose programming language. It looks like this problem is going to be solved over time by making OpenSCAD more like a functional programming language. In the most recent edition, we added list comprehensions and 'let' expressions, which came directly from functional programming. There is general agreement that these changes made OpenSCAD much more powerful. But we still have a ways to go. I've written up a proposal/roadmap called "openscad2", which proposes a way to evolve OpenSCAD into a more powerful geometric description language, by adding more of the features of functional programming languages, and without breaking backwards compatibility. https://github.com/doug-moen/openscad2 You say that you are most comfortable programming in Perl. That means you have learned enough of the Perl idioms so that you can be productive in that language. Functional programming languages use a different set of idioms, and you have to learn those idioms in order to be productive in those languages. If you put in the effort to learn this new style of programming, you'll find it is more powerful than the old way of doing things. And yes, I do see a lot of momentum behind the functional programming movement, I think it is transforming the industry. New programming languages are incorporating more and more of the idioms of functional programming. I see this in Apple's new language Swift, Mozilla's new language Rust, even Perl 6. On 15 November 2015 at 08:36, rickan <[hidden email]> wrote: I really feel I should add my vote against these silly immutable variables. _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org |
In reply to this post by rickan
This is all about philosophy. The argument "All programming languages I have used do it differently" is irrelevant. Of the many languages I have used, all have some features you learn to live with.
OpenSCAD has a very valid reason for doing what it does. My vote is to leave it alone.
Larry
|
Administrator
|
In reply to this post by rickan
> On Nov 15, 2015, at 08:36 AM, rickan <[hidden email]> wrote: > > I really feel I should add my vote against these silly immutable variables. > General purpose programming can be done in a language-specific framework, similar to how you’d use such frameworks to generate HTML, rather than modifying the HTML spec to support certain dynamic features. I’m not advocating any particular languages. I’ll just mention the ruby-based CrystalSCAD as an example, because I had the pleasure to chat with the author a few months back: https://github.com/Joaz/CrystalScad Now, I’m open to support a plugin infrastructure to allow writing such code in the OpenSCAD environment, if that’s something people really want to do. We could even support people writing modules in other languages, as long as modules follow the same rules of not mutating its host environment. I feel that most people familiar with certain programming languages would rather use the extended feature set of that language environment, so I’m not sure how effective this would be. -Marius > <rant> > It really is silly, it makes some very, very useful things that are trivial > to do with regular variables seemingly impossible in openscad, and I can't > imagine it's good for beginning programmers or people who do it > infrequently. It seems obvious what if you want OpenSCAD to be as widely > adopted as possible, you will drop this immutable variable ideology. Find > some other way to advocate the functional programming ideology. > > I'm retired from doing programming for a living, and I've never been > impressed with the "problems" that functional programming is supposed to be > a solution for, nor is it apparent to me that it's been widely adopted to > solve those "problems". > > I'm sure these ideas have already been thoroughly hashed in this thread > (which I don't have the patience to read) -- this is just my vote. > > P.S. I'm a Perl programmer when given a choice because the Perl ideology is > "There is more than one way to do it" and I can choose the way that's best > for me, for each of projects of widely various character, from what seems to > be a very nearly complete set of tools including some which impose > programming restrictions for those who seem to need them. I've never found > it wanting and can't recall the language interposing itself as part of the > problem the way I can other other languages. > > P.P.S. I'm certainly NOT advocating for making the OpenSCAD language as > universal as Perl. I'm not very experienced with it and probably never will > be, but it seems to be more than adequate for solid modelling except for > those silly... > </rant> > > > > > -- > View this message in context: http://forum.openscad.org/Plans-to-change-variable-behavior-tp9647p14508.html > Sent from the OpenSCAD mailing list archive at Nabble.com. > > _______________________________________________ > OpenSCAD mailing list > [hidden email] > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org |
Here is my attempt at explaining functional programming to myself.
https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/General_%28by_c.t.chin%29#Basic_Concepts I'm with kintel here. While I find declarative programming to very restrictive and inconvenient, I can sense that catastrophe awaits if the development team agrees to change to or allow even limited procedural computation. My solution to enable iterative computation or logic in OpenSCAD is to use Matlab (you could do VC, perl, Python whatever) for the computation and "export" the answer(s) to OpenSCAD by generating OpenSCAD code. Matlab may not be a well-known language, but its code is easy enough to understand, following generate an OpenSCAD polyhedron module from Matlab: function outstr = openscad(fid, modname, objs); fprintf(fid, 'module %s() { union() {\n', modname); for o = objs; // for each object o nv = size(o.verts, 1); nf = numel(o.faces); fprintf(fid, 'polyhedron(\n points = [\n'); for kv = 1:nv fprintf(fid, ' [%g, %g, %g],\n', o.verts(kv,1), o.verts(kv,2), o.verts(kv,3)); end; fseek(fid,-2,0); % remove the last comma and newline fprintf(fid, '\n ],\n'); fprintf(fid, ' faces = [\n'); for kf = 1:nf; m = sprintf('%d, ', o.faces(kf).vi-1); m = m(1:end-2); fprintf(fid, ' [%s],\n',m); end fseek(fid,-2,0); % remove the last comma and newline fprintf(fid, '\n ]\n);\n'); end fprintf(fid, '} } \n'); |
In reply to this post by L Boyd
In the instance which aroused my desire to vote against immutable variables, the location of my primitive call, cube(), in the inner of 3 nested for ops, is ideal for calculating various properties of the cube for that specific call and for counting the numbers of cubes with the same properties, etc.
The reasons, in addition to immutable variables, I can't to that is that modules do not return anything and modules cannot be called within functions. I can do it by writing other functions to be called on the list equivalent of the three nested for ops with the same conditionals resulting in horrible code proliferation with it's attendant pitfalls. Or I can just write it in Perl which spews huge volumes of module calls generated in the 3 nested for loops in which case features of the OpenSCAD language such as immutable variables are irrelevant. I read parts of your OpenSCAD 2 proposal with interest. Most relevant is that the only distinction between functions and modules is what they return, i.e. functions return anything at all and modules return geometrical objects. (Please correct any error in my understanding.) I would like to suggest that modules return objects which contain the geometrical object in addition to a user definable, user settable, set of key => value pairs, i.e. user definable meta-data the module produces. It might make sense that some of the keys would be standard e.g. the key for the geometrical object itself, the parameters passed to the call including children objects, the coordinate transform matrix of the call, the color, etc.; but whether or not that is done, the user should be able to augment the set. If this were done, then aggregation of the meta-data could be accomplished by calling functions on lists of these module produced objects. What I'm calling meta-data here is, I think, a very important part of solid modeling. Here's my specific case: Wallis.scad inserted here for convenience: // Copyright 2015 Richard Kandarian http://kandarian.com/ function mkp(p, n, m) = n>m ? p : mkp(concat(p, [p[len(p)-1]*(2*n-1)/(2*n-2)]), n+1, m); function mka(a, n, m) = n>m ? a : mka(concat(a, [a[len(a)-1]*(2*n-1)/(2*n)]), n+1, m); function shift(o, v) = [for(i=[o:len(v)-1]) v[i]]; function hsv2rgb(h, s, v) = let(hs=h/60, f=hs-floor(hs), p=v*(1-s), q=v*(1-s*f), t=v*(1-s*(1-f))) h>=0 && h<60 ? [v, t, p] : ( h>=60 && h<120 ? [q, v, p] : ( h>=120 && h<180 ? [p, v, t] : ( h>=180 && h<240 ? [p, q, v] : ( h>=240 && h<300 ? [t, p, v] : [v, p, q] ) ) ) ); m = 50; hollow = 1; thick = 1; p = mkp([1], 2, m); pl = len(p)-1; a = concat([1], shift(1, mka([1], 1, m-1))); al = len(a)-1; //echo(pl, p); //echo(al, a); module octant(){ for(zi = [0:pl]){ zm = pl-zi; z = zm<1 ? 0 : p[zm-1]; h = a[zm]; // hv1 = zm/m*360+(zm%2)*120; // hv = hv1 > 360 ? hv1-360 : hv1; for(yi = [0:zi]){ ym = zi-yi; y = ym<1 ? 0 : p[ym-1]; l = a[ym]; for(xi = [0:yi]){ xm = yi-xi; x = xm<1 ? 0 : p[xm-1]; w = a[xm]; if(!hollow || abs(xm+ym-zi) < thick){ hv1 = (xm+ym)/m*360+(zm%2)*120; hv = hv1 > 360 ? hv1-360 : hv1; translate([x, y, z]){ color(hsv2rgb(hv, .3, 1)){ cube([w, l, h], center=false); }; }; } } } } } module hemi(){ octant(); rotate([0,0,90]) octant(); rotate([0,0,180]) octant(); rotate([0,0,270]) octant(); } //hull(){ hemi(); rotate([180,0,0]) hemi(); //} |
Hmmm, Seems I hit the wrong reply button. I meant to reply to Doug Moen.
|
It's okay, I got the message. And I'll try to respond. On 16 November 2015 at 13:53, rickan <[hidden email]> wrote: Hmmm, Seems I hit the wrong reply button. I meant to reply to Doug Moen. _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org |
In reply to this post by rickan
rickan said: That is correct. The distinction between modules and functions disappears,> I read parts of your OpenSCAD 2 proposal with interest. Most relevant is > that the only distinction between functions and modules is what they return, > i.e. functions return anything at all and modules return geometrical > objects. (Please correct any error in my understanding.) > I would like to suggest that modules return objects which contain the > geometrical object in addition to a user definable, user settable, set of > key => value pairs, i.e. user definable meta-data the module produces. It > might make sense that some of the keys would be standard e.g. the key for > the geometrical object itself, the parameters passed to the call including > children objects, the coordinate transform matrix of the call, the color, > etc.; but whether or not that is done, the user should be able to augment > the set. All keys within a geometric object are user defined. But otherwise, it works as you have described.https://github.com/doug-moen/openscad2/blob/master/rfc/Objects.md two kinds of geometric values, both represent a 2D or 3D figure. On 16 November 2015 at 13:47, rickan <[hidden email]> wrote: In the instance which aroused my desire to vote against immutable variables, _______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org |
Doug Moen said:
> rickan, again: > > I would like to suggest that modules return objects which contain the > > geometrical object in addition to a user definable, user settable, set of > > key => value pairs, i.e. user definable meta-data the module produces. It > > might make sense that some of the keys would be standard e.g. the key for > > the geometrical object itself, the parameters passed to the call including > > children objects, the coordinate transform matrix of the call, the color, > > etc.; but whether or not that is done, the user should be able to augment > > the set. > > That is pretty much how the OpenSCAD2 design already works. > I have not made any attempt to define "standard keys", and in the present design, > primitive shapes like the ones returned by cube() and sphere() don't have any keys. > All keys within a geometric object are user defined. > But otherwise, it works as you have described. > > Here is the section that describes "geometric objects": > https://github.com/doug-moen/openscad2/blob/master/rfc/Objects.md It doesn't look that way to me because I only see how parameters are input to the object, not how the object creates values (meta-data) and stores them for later use as a result of the module call or object instantiation, e.g, volume or moment of inertia calculated from the input parameters. In my code example where the cube() is called inside if{!hollow... if I were to take that if block and put it in a module or object with all the required input parameters, I could, in that module, calculate and store the volume of the cube, it's moment of inertia, and I could store the color for access and analysis in some other part of my program. |
Okay, let me explain how it works. Now lets consider your octant module:In OpenSCAD2, an object is delimited by {...}. It may contain definitions, like 'zm = pl-zi;' from your octant module, and it may contain geometry statements, like 'translate(..) color(..) cube(..)' from your octant module. Definitions add key-value pairs to the object, while geometry statements add geometry. module octant(){ for(zi = [0:pl]){ zm = pl-zi; z = zm<1 ? 0 : p[zm-1]; h = a[zm]; for(yi = [0:zi]){ ym = zi-yi; y = ym<1 ? 0 : p[ym-1]; l = a[ym]; for(xi = [0:yi]){ xm = yi-xi; x = xm<1 ? 0 : p[xm-1]; w = a[xm]; if(!hollow || abs(xm+ym-zi) < thick){ hv1 = (xm+ym)/m*360+(zm%2)*120; hv = hv1 > 360 ? hv1-360 : hv1; translate([x, y, z]){ color(hsv2rgb(hv, .3, 1)){ cube([w, l, h], center=false); }; }; } } } } }There are lots of {...} object literals in this module, so the result will be a nested tree of objects. L0: the top level object contains a list of objects generated by 'for (zi=...)' On 16 November 2015 at 14:53, rickan <[hidden email]> wrote:
_______________________________________________ OpenSCAD mailing list [hidden email] http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org |
Okay!
That will work very nicely! |
Free forum by Nabble | Edit this page |