discuss@lists.openscad.org

OpenSCAD general discussion

View all threads

OO patterns in OpenSCAD

N
NateTG
Sat, Apr 3, 2021 4:01 PM

Recently, I've been thinking that it would be nice if there were some syntax
hack that made:

function.text

equivalent to something like

function($dot="text")

for function literals in openSCAD.

That would allow for the creations of things like color triplets in user
space:

function rgbtriplet($dot=undef,r=undef,g=undef,b=undef)=
($dot=="new")?
function($dot) rgbtriplet($dot=$dot,r=r,g=g,b=b)
:($dot=="r" || $dot=="R" || $dot=="red")?
r
:($dot=="g" || $dot=="G" || $dot=="green")?
g
: // ($dot=="b" || $dot=="B" || $dot=="blue")?
b
;

my rgb=rgbtriplet.new(r=128,g=64,b=255);
echo(rgb.r);

Function literals already allow this kind of programming pattern, but the
existing syntax for doing it is pretty awkward.

We already have the dot notation for lists.  So "dot syntax" isn't out of
line for OpenSCAD. On the other hand, it might be that the way that dot
notation for lists is implemented makes this kind of thing much harder to do
to.

Regardless, I'm wondering whether:

  1. People think this is a terrible idea or not in principle.

  2. People think that this kind of thing is hard to implement or not.

--
Sent from: http://forum.openscad.org/

Recently, I've been thinking that it would be nice if there were some syntax hack that made: > function.text equivalent to something like > function($dot="text") for function literals in openSCAD. That would allow for the creations of things like color triplets in user space: >function rgbtriplet($dot=undef,r=undef,g=undef,b=undef)= > ($dot=="new")? > function($dot) rgbtriplet($dot=$dot,r=r,g=g,b=b) > :($dot=="r" || $dot=="R" || $dot=="red")? > r > :($dot=="g" || $dot=="G" || $dot=="green")? > g > : // ($dot=="b" || $dot=="B" || $dot=="blue")? > b >; > >my rgb=rgbtriplet.new(r=128,g=64,b=255); >echo(rgb.r); Function literals already allow this kind of programming pattern, but the existing syntax for doing it is pretty awkward. We already have the dot notation for lists. So "dot syntax" isn't out of line for OpenSCAD. On the other hand, it might be that the way that dot notation for lists is implemented makes this kind of thing much harder to do to. Regardless, I'm wondering whether: 1. People think this is a terrible idea or not in principle. 2. People think that this kind of thing is hard to implement or not. -- Sent from: http://forum.openscad.org/
JB
Jordan Brown
Sun, Apr 4, 2021 1:58 PM

There is some related commentary in the "Discuss Function literals &
Objects etc" issue at https://github.com/openscad/openscad/issues/3088 .

There is some related commentary in the "Discuss Function literals & Objects etc" issue at https://github.com/openscad/openscad/issues/3088 .
DM
Doug Moen
Sun, Apr 4, 2021 5:19 PM

There has been a separate forum discussion about adding syntax for record literals, which might look something like this:

rgb =  {r: 128, g: 64, b: 255};

and then you can use expressions like 'rgb.r'. I think this approach is simpler and more ergonomic than requiring people to encode records using functions.

On Sat, Apr 3, 2021, at 12:01 PM, NateTG wrote:

Recently, I've been thinking that it would be nice if there were some syntax hack that made:

function.text

equivalent to something like

function($dot="text")

for function literals in openSCAD.

That would allow for the creations of things like color triplets in user space:

function rgbtriplet($dot=undef,r=undef,g=undef,b=undef)=
($dot=="new")?
function($dot) rgbtriplet($dot=$dot,r=r,g=g,b=b)
:($dot=="r" || $dot=="R" || $dot=="red")?
r
:($dot=="g" || $dot=="G" || $dot=="green")?
g
: // ($dot=="b" || $dot=="B" || $dot=="blue")?
b
;

my rgb=rgbtriplet.new(r=128,g=64,b=255);
echo(rgb.r);

Function literals already allow this kind of programming pattern, but the existing syntax for doing it is pretty awkward.

We already have the dot notation for lists.  So "dot syntax" isn't out of line for OpenSCAD. On the other hand, it might be that the way that dot notation for lists is implemented makes this kind of thing much harder to do to.

Regardless, I'm wondering whether:

  1. People think this is a terrible idea or not in principle.

  2. People think that this kind of thing is hard to implement or not.

Sent from the OpenSCAD mailing list archive http://forum.openscad.org/ at Nabble.com.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org mailto:discuss-leave%40lists.openscad.org

There has been a separate forum discussion about adding syntax for record literals, which might look something like this: rgb = {r: 128, g: 64, b: 255}; and then you can use expressions like 'rgb.r'. I think this approach is simpler and more ergonomic than requiring people to encode records using functions. On Sat, Apr 3, 2021, at 12:01 PM, NateTG wrote: > Recently, I've been thinking that it would be nice if there were some syntax hack that made: > > > function.text > > equivalent to something like > > > function($dot="text") > > for function literals in openSCAD. > > That would allow for the creations of things like color triplets in user space: > > >function rgbtriplet($dot=undef,r=undef,g=undef,b=undef)= > > ($dot=="new")? > > function($dot) rgbtriplet($dot=$dot,r=r,g=g,b=b) > > :($dot=="r" || $dot=="R" || $dot=="red")? > > r > > :($dot=="g" || $dot=="G" || $dot=="green")? > > g > > : // ($dot=="b" || $dot=="B" || $dot=="blue")? > > b > >; > > > >my rgb=rgbtriplet.new(r=128,g=64,b=255); > >echo(rgb.r); > > Function literals already allow this kind of programming pattern, but the existing syntax for doing it is pretty awkward. > > We already have the dot notation for lists. So "dot syntax" isn't out of line for OpenSCAD. On the other hand, it might be that the way that dot notation for lists is implemented makes this kind of thing much harder to do to. > > Regardless, I'm wondering whether: > > 1. People think this is a terrible idea or not in principle. > > 2. People think that this kind of thing is hard to implement or not. > > > Sent from the OpenSCAD mailing list archive <http://forum.openscad.org/> at Nabble.com. > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org <mailto:discuss-leave%40lists.openscad.org> >
M
MichaelAtOz
Sun, Apr 4, 2021 11:23 PM

doug.moen wrote

rgb =  {r: 128, g: 64, b: 255};

Please not curly brackets in another context.


OpenSCAD Admin - email* me if you need anything,  or if I've done something stupid...

  • on the Forum, click on my MichaelAtOz label, there is a link to email me.

Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work. Obviously inclusion of works of previous authors is not included in the above.

--
Sent from: http://forum.openscad.org/

doug.moen wrote > rgb = {r: 128, g: 64, b: 255}; Please not curly brackets in another context. ----- OpenSCAD Admin - email* me if you need anything, or if I've done something stupid... * on the Forum, click on my MichaelAtOz label, there is a link to email me. Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work. Obviously inclusion of works of previous authors is not included in the above. -- Sent from: http://forum.openscad.org/
RD
Revar Desmera
Mon, Apr 5, 2021 4:57 AM

For consideration, I’ve created a function-literal pseudo-class for implementing hashmaps, where the arguments used specify the action taken:

hm = hashmap(items=[for (i=[0:9999]) [str("foo",i),i]]);
a = hm("foo37");  // Returns: 37
hm2 = hm("Blah", 39);  // Adds entry "Blah" with val 39.
b = hm2("Blah");  // Returns: 39
hm3 = hm2(additems=[["bar",39],["qux",21]]);  // Adds "bar" and "qux"
hm4 = hm3(del="Blah");  // Deletes entry "Blah".
for (kv = hm4()) {  // Iterates over all key/value pairs.
echo(key=kv[0], val=kv[1]);
}

function simple_hash(x) =
let( m = 0.5 * (sqrt(5) - 1) )
is_num(x)? floor(mx256) :
is_list(x)? let(
l = len(x),
a = function(i,v) i>=l? v : a(i+1, m*v + simple_hash(x[i]))
) floor(a(0,0)4096) : let(
s = str(x),
l = len(s),
a = function(i,v) i>=l? v : a(i+1, m
v + ord(s[i]))
) floor(a(0,0)*4096);

function idx(l) = [0:1:len(l)-1];  // Simplified from BOSL2 code.

// Declaring group_data() in terms not requiring BOSL2 is a lot more complicated
// and will not be included here.  It's only used for items= and additems=.

function hashmap(hashsize=127,items,table) =
let(
table = !is_undef(table)? table : [for (i=[0:1:hashsize-1]) []]
)
items != undef? hashmap(hashsize=hashsize, table=table)(additems=items) :
function(k,v,del,additems)
additems!=undef? let(
hashes = [for (item = additems) simple_hash(item[0]) % hashsize],
grouped = list_pad(group_data(hashes, additems), hashsize, []),
table = [for (i=idx(table)) concat(table[i],grouped[i])]
) hashmap(hashsize=hashsize, table=table) :
del!=undef? let(
bnum = simple_hash(del) % hashsize,
bucket = [for (item=table[bnum]) if (item[0]!=del) item],
table = [for (i=idx(table)) i==bnum? bucket : table[i]]
) hashmap(hashsize=hashsize, table=table) :
k==undef && v==undef? [for (bucket=table, item=bucket) item] :
let(
bnum = simple_hash(k) % hashsize,
bucket = table[bnum],
fnd = search([k], bucket)
)
k!=undef && v==undef? (fnd==[]? undef : bucket[fnd[0]][1]) :
let(
newtable = [
for (i=idx(table))
i!=bnum? table[i] :
!fnd? [[k,v], each bucket] :
[[k,v], for (j=idx(bucket)) if (j!=fnd[0]) bucket[i]]
]
) hashmap(hashsize=hashsize, table=newtable);

  • Revar

On Apr 3, 2021, at 9:01 AM, NateTG nate-openscadforum@pedantic.org wrote:

Recently, I've been thinking that it would be nice if there were some syntax hack that made:

function.text

equivalent to something like

function($dot="text")

for function literals in openSCAD.

That would allow for the creations of things like color triplets in user space:

function rgbtriplet($dot=undef,r=undef,g=undef,b=undef)=
($dot=="new")?
function($dot) rgbtriplet($dot=$dot,r=r,g=g,b=b)
:($dot=="r" || $dot=="R" || $dot=="red")?
r
:($dot=="g" || $dot=="G" || $dot=="green")?
g
: // ($dot=="b" || $dot=="B" || $dot=="blue")?
b
;

my rgb=rgbtriplet.new(r=128,g=64,b=255);
echo(rgb.r);

Function literals already allow this kind of programming pattern, but the existing syntax for doing it is pretty awkward.

We already have the dot notation for lists.  So "dot syntax" isn't out of line for OpenSCAD. On the other hand, it might be that the way that dot notation for lists is implemented makes this kind of thing much harder to do to.

Regardless, I'm wondering whether:

  1. People think this is a terrible idea or not in principle.

  2. People think that this kind of thing is hard to implement or not.

Sent from the OpenSCAD mailing list archive http://forum.openscad.org/ at Nabble.com.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

For consideration, I’ve created a function-literal pseudo-class for implementing hashmaps, where the arguments used specify the action taken: hm = hashmap(items=[for (i=[0:9999]) [str("foo",i),i]]); a = hm("foo37"); // Returns: 37 hm2 = hm("Blah", 39); // Adds entry "Blah" with val 39. b = hm2("Blah"); // Returns: 39 hm3 = hm2(additems=[["bar",39],["qux",21]]); // Adds "bar" and "qux" hm4 = hm3(del="Blah"); // Deletes entry "Blah". for (kv = hm4()) { // Iterates over all key/value pairs. echo(key=kv[0], val=kv[1]); } function simple_hash(x) = let( m = 0.5 * (sqrt(5) - 1) ) is_num(x)? floor(m*x*256) : is_list(x)? let( l = len(x), a = function(i,v) i>=l? v : a(i+1, m*v + simple_hash(x[i])) ) floor(a(0,0)*4096) : let( s = str(x), l = len(s), a = function(i,v) i>=l? v : a(i+1, m*v + ord(s[i])) ) floor(a(0,0)*4096); function idx(l) = [0:1:len(l)-1]; // Simplified from BOSL2 code. // Declaring group_data() in terms not requiring BOSL2 is a lot more complicated // and will not be included here. It's only used for `items=` and `additems=`. function hashmap(hashsize=127,items,table) = let( table = !is_undef(table)? table : [for (i=[0:1:hashsize-1]) []] ) items != undef? hashmap(hashsize=hashsize, table=table)(additems=items) : function(k,v,del,additems) additems!=undef? let( hashes = [for (item = additems) simple_hash(item[0]) % hashsize], grouped = list_pad(group_data(hashes, additems), hashsize, []), table = [for (i=idx(table)) concat(table[i],grouped[i])] ) hashmap(hashsize=hashsize, table=table) : del!=undef? let( bnum = simple_hash(del) % hashsize, bucket = [for (item=table[bnum]) if (item[0]!=del) item], table = [for (i=idx(table)) i==bnum? bucket : table[i]] ) hashmap(hashsize=hashsize, table=table) : k==undef && v==undef? [for (bucket=table, item=bucket) item] : let( bnum = simple_hash(k) % hashsize, bucket = table[bnum], fnd = search([k], bucket) ) k!=undef && v==undef? (fnd==[]? undef : bucket[fnd[0]][1]) : let( newtable = [ for (i=idx(table)) i!=bnum? table[i] : !fnd? [[k,v], each bucket] : [[k,v], for (j=idx(bucket)) if (j!=fnd[0]) bucket[i]] ] ) hashmap(hashsize=hashsize, table=newtable); - Revar > On Apr 3, 2021, at 9:01 AM, NateTG <nate-openscadforum@pedantic.org> wrote: > > Recently, I've been thinking that it would be nice if there were some syntax hack that made: > > > function.text > > equivalent to something like > > > function($dot="text") > > for function literals in openSCAD. > > That would allow for the creations of things like color triplets in user space: > > >function rgbtriplet($dot=undef,r=undef,g=undef,b=undef)= > > ($dot=="new")? > > function($dot) rgbtriplet($dot=$dot,r=r,g=g,b=b) > > :($dot=="r" || $dot=="R" || $dot=="red")? > > r > > :($dot=="g" || $dot=="G" || $dot=="green")? > > g > > : // ($dot=="b" || $dot=="B" || $dot=="blue")? > > b > >; > > > >my rgb=rgbtriplet.new(r=128,g=64,b=255); > >echo(rgb.r); > > Function literals already allow this kind of programming pattern, but the existing syntax for doing it is pretty awkward. > > We already have the dot notation for lists. So "dot syntax" isn't out of line for OpenSCAD. On the other hand, it might be that the way that dot notation for lists is implemented makes this kind of thing much harder to do to. > > Regardless, I'm wondering whether: > > 1. People think this is a terrible idea or not in principle. > > 2. People think that this kind of thing is hard to implement or not. > > > Sent from the OpenSCAD mailing list archive <http://forum.openscad.org/> at Nabble.com. > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org
RD
Revar Desmera
Mon, Apr 5, 2021 5:43 AM

More entertaining things to do with function literals.  Making function generators to optionally pre-fill out arbitrary arguments of existing functions that take 1 to 3 args:

f_add = f_2arg(function(a,b) a+b);
f_mul = f_2arg(function(a,b) a*b);
f_lt = f_2arg(function(a,b) a<b);

fn_lt = f_lt();    // = function(a,b) a<b;
fn_lt3 = f_lt(3);    // = function(a) a<3;
fn_3lt = f_lt(a=3);    // = function(b) 3<b;
fn_3lt4 = f_lt(a=3,b=4); // = function() 3<4; Not very useful, but symmetric.

lt10 = function(list) filter(f_lt(10), list);
inv = function(list) map(f_div(a=1), list);
sum = function(list) reduce(f_sdd(), list);
prod = function(list) reduce(f_mul(), list);
cumul_prod = function(list) accumulate(f_mul(), list);

function map(func, list) = [for (x=list) func(x)];

function filter(func, list) = [for (x=list) if (func(x)) x];

function reduce(func, list, init=0) =
let(
l = len(list),
a = function (x,i) i<l? a(func(x,list[i]), i+1) : x
) a(init,0);

function accumulate(func, list, init=0) =
let(
l = len(list),
a = function (x, i, out)
i >= l ? out :
let( x=func(x,list[i]) )
a(x, i+1, [each out, x])
) a(init, 0, []);

function f_1arg(func) =
function(a)
a==undef? func :
function() func(a);

function f_2arg(func) =
function(b,a)
a==undef && b==undef? func :
a==undef? function(x) func(x,b) :
b==undef? function(x) func(a,x) :
function() func(a,b);

function f_3arg(func) =
function(a,b,c)
a==undef && b==undef && c==undef? func :
a==undef && b==undef? function(x,y) func(x,y,c) :
a==undef && c==undef? function(x,y) func(x,b,y) :
b==undef && c==undef? function(x,y) func(a,x,y) :
a==undef? function(x) func(x,b,c) :
b==undef? function(x) func(a,x,c) :
c==undef? function(x) func(a,b,x) :
function() func(a,b,c);

  • Revar
More entertaining things to do with function literals. Making function generators to optionally pre-fill out arbitrary arguments of existing functions that take 1 to 3 args: f_add = f_2arg(function(a,b) a+b); f_mul = f_2arg(function(a,b) a*b); f_lt = f_2arg(function(a,b) a<b); fn_lt = f_lt(); // = function(a,b) a<b; fn_lt3 = f_lt(3); // = function(a) a<3; fn_3lt = f_lt(a=3); // = function(b) 3<b; fn_3lt4 = f_lt(a=3,b=4); // = function() 3<4; Not very useful, but symmetric. lt10 = function(list) filter(f_lt(10), list); inv = function(list) map(f_div(a=1), list); sum = function(list) reduce(f_sdd(), list); prod = function(list) reduce(f_mul(), list); cumul_prod = function(list) accumulate(f_mul(), list); function map(func, list) = [for (x=list) func(x)]; function filter(func, list) = [for (x=list) if (func(x)) x]; function reduce(func, list, init=0) = let( l = len(list), a = function (x,i) i<l? a(func(x,list[i]), i+1) : x ) a(init,0); function accumulate(func, list, init=0) = let( l = len(list), a = function (x, i, out) i >= l ? out : let( x=func(x,list[i]) ) a(x, i+1, [each out, x]) ) a(init, 0, []); function f_1arg(func) = function(a) a==undef? func : function() func(a); function f_2arg(func) = function(b,a) a==undef && b==undef? func : a==undef? function(x) func(x,b) : b==undef? function(x) func(a,x) : function() func(a,b); function f_3arg(func) = function(a,b,c) a==undef && b==undef && c==undef? func : a==undef && b==undef? function(x,y) func(x,y,c) : a==undef && c==undef? function(x,y) func(x,b,y) : b==undef && c==undef? function(x,y) func(a,x,y) : a==undef? function(x) func(x,b,c) : b==undef? function(x) func(a,x,c) : c==undef? function(x) func(a,b,x) : function() func(a,b,c); - Revar
N
NateTG
Mon, Apr 5, 2021 12:43 PM

doug.moen wrote

There has been a separate forum discussion about adding syntax for record
literals, which might look something like this:

rgb =  {r: 128, g: 64, b: 255};

and then you can use expressions like 'rgb.r'. I think this approach is
simpler and more ergonomic than requiring people to encode records using
functions.
...

Thank you for the feedback.

I see that that's more convenient and legible than something like:

include<dict.scad>
....
rgb=dict( [ ["r",128],["g",64],["b",255] ]);

How well does what you proposed fit with the existing OpenSCAD syntax?

Is there some philosophical guideline about whether stuff should be done "in
OpenSCAD" or "in userspace"?  (I'm not sure whether that's the right
terminology.)

Should "r","g", and "b" have been in quotes in the example that you gave?
Are you looking for something that effectively just adds "rgb.r", "rgb.g"
and "rgb.b" as variables to the current scope, or do you care about things
like iterating over key value pairs, or code-generated keys?

When you write "simpler" do you mean "easier for me to use and read" or
something else?

--
Sent from: http://forum.openscad.org/

doug.moen wrote > There has been a separate forum discussion about adding syntax for record > literals, which might look something like this: > > rgb = {r: 128, g: 64, b: 255}; > > and then you can use expressions like 'rgb.r'. I think this approach is > simpler and more ergonomic than requiring people to encode records using > functions. > ... Thank you for the feedback. I see that that's more convenient and legible than something like: include<dict.scad> .... rgb=dict( [ ["r",128],["g",64],["b",255] ]); How well does what you proposed fit with the existing OpenSCAD syntax? Is there some philosophical guideline about whether stuff should be done "in OpenSCAD" or "in userspace"? (I'm not sure whether that's the right terminology.) Should "r","g", and "b" have been in quotes in the example that you gave? Are you looking for something that effectively just adds "rgb.r", "rgb.g" and "rgb.b" as variables to the current scope, or do you care about things like iterating over key value pairs, or code-generated keys? When you write "simpler" do you mean "easier for me to use and read" or something else? -- Sent from: http://forum.openscad.org/
N
NateTG
Mon, Apr 5, 2021 12:53 PM

RevarBat wrote

For consideration, I’ve created a function-literal pseudo-class for
implementing hashmaps, where the arguments used specify the action taken:
...

Thank you.

Do you have any opinion about whether something like "function dot" syntax
in OpenSCAD would be a good idea or not?

Do you have any sense about whether "function dot" syntax would be hard to
implement?

--
Sent from: http://forum.openscad.org/

RevarBat wrote > For consideration, I’ve created a function-literal pseudo-class for > implementing hashmaps, where the arguments used specify the action taken: > ... Thank you. Do you have any opinion about whether something like "function dot" syntax in OpenSCAD would be a good idea or not? Do you have any sense about whether "function dot" syntax would be hard to implement? -- Sent from: http://forum.openscad.org/
RW
Ray West
Mon, Apr 5, 2021 2:12 PM

On 05/04/2021 13:43, NateTG wrote:

How well does what you proposed fit with the existing OpenSCAD syntax?

Is there a 'formal definition' of the syntax anywhere, or has it just
evolved, bit's added as needed?

On 05/04/2021 13:43, NateTG wrote: > How well does what you proposed fit with the existing OpenSCAD syntax? Is there a 'formal definition' of the syntax anywhere, or has it just evolved, bit's added as needed?
N
NateTG
Mon, Apr 5, 2021 3:29 PM

mondo wrote

On 05/04/2021 13:43, NateTG wrote:

How well does what you proposed fit with the existing OpenSCAD syntax?

Is there a 'formal definition' of the syntax anywhere, or has it just
evolved, bit's added as needed?

I'm not aware of any formal design documents.  I looked through the usual
documentation a bit to see what the restrictions on variable identifiers are
at ( http://www.openscad.org/documentation.html) as part of thinking about
this question and didn't come up with anything.

In another sense, the language grammar is formally defined in the
src/lexer.l and src/parser.y files.  So, for example, it looks like
identifiers follow the regexp:  $"?[a-zA-Z0-9_]+ based on line 256 of
lexer.l.  I'm not sophisticated enough to figure out where the ".x" stuff
is in there.

--
Sent from: http://forum.openscad.org/

mondo wrote > On 05/04/2021 13:43, NateTG wrote: >> How well does what you proposed fit with the existing OpenSCAD syntax? > > Is there a 'formal definition' of the syntax anywhere, or has it just > evolved, bit's added as needed? I'm not aware of any formal design documents. I looked through the usual documentation a bit to see what the restrictions on variable identifiers are at ( http://www.openscad.org/documentation.html) as part of thinking about this question and didn't come up with anything. In another sense, the language grammar is formally defined in the src/lexer.l and src/parser.y files. So, for example, it looks like identifiers follow the regexp: $"?[a-zA-Z0-9_]+ based on line 256 of lexer.l. I'm not sophisticated enough to figure out where the ".x" stuff is in there. -- Sent from: http://forum.openscad.org/