Hi,

Guest

JB

Jordan Brown

Sat, Sep 3, 2022 3:33 AM

On 9/2/2022 5:53 PM, Andy Little via Discuss wrote:

For now, accessing the member assignments of a module_alias with

parameters without instantiation into the CSG tree is just a case of

reusing the same syntax that you can use to access the assignments of

a module:

module television(size, b) { diagonal = sqrt( size.x^2 + size.y^2);}

|diagonal = module m([30,20]).diagonal; // an anonymous module_alias|

|m = module (size) television(size, 2); // named alias diagonal1 =

module m([30,20]).diagonal;|

So I think we're getting at least sort of close to a mutual understanding.

I see a couple of points there where I have trouble.

- Getting the value of "diagonal" requires evaluating the module's

assignments. I can't see doing that unless we also evaluate its

module invocations. (That*does*happen in a couple of obscure

cases in OpenSCAD, but I wouldn't want to make it be a primary

case.) But evaluating the module invocations doesn't necessarily

mean putting the geometry into the model. It could go into a

geometry-as-data structure that might or might not eventually end up

as part of the model. - I don't think that either "diagonal" or "diagonal1" above require

special syntax, if we have geometry-as-data and a way to peek at the

as-evaluated local variables. m([30,20]) would evaluate the module

with the specified argument, returning some kind of structure that

includes both the as-evaluated local variables and the geometry, and

then you could look at the "diagonal" local variable. (But see below.) - The middle line, the "m=" line, has only a single module invocation

in it. But what if it had more than one module invocation? What if

it was { television(size); credenza(size); }?

That last one is the hardest.

In any other OpenSCAD context, anywhere that you can have a module

invocation, you can have a { ... } block with any number of assignments

and module invocations. Also, a single module invocation is equivalent

to that same module invocation with braces around it.

That is:

```
translate([10,0,0]) cube(10);
translate([10,0,0]) { cube(10); }
```

are equivalent. Similarly:

```
module box(size) cube(size);
module box(size) { cube(size); }
```

are equivalent.

So if you can have

```
m = module (size) television(size);
```

then you could also have

```
m = module (size) { television(size); };
```

and

```
m = module (size) { television(size); credenza(size); };
```

and then what would m([30,20]).xxx mean? Would it peek inside

television's local variables, or credenza's? Or the (empty in this

case) local variables for the { ... } block?

And if there's no good answer for that (and I don't think there is), then

```
m = module (size) { television(size); };
```

is also in trouble. And if *that's* in trouble, by the equivalence above,

```
m = module (size) television(size);
```

is in trouble.

What I've played with so far is

```
o = { diagonal = sqrt(16^2 + 9^2); square([16,9]); };
```

which is *not* a module; it's an expression that evaluates some

assignments and some geometry and returns the result as an object. You

can then say "o.diagonal" and get 18-point-something.

That alone has some interesting effects, because since it is an

expression it can be returned by a function and it can use a function's

arguments in its evaluation:

```
function television(size) = {
diagonal = sqrt( size.x^2 + size.y^2);
square(size);
};
```

and then you could talk about television(size).diagonal, which would

evaluate the function, evaluate the object, evaluate the assignment and

the geometry, return "diagonal" and the square, discard the square, and

return "diagonal".

```
In the discussion above I've concentrated on retrieving the values
from the evaluation, and ignored the geometry. Given o above, or
the television() function, how would you get the geometry added to
the model? So far the best answer seems to be that the render()
module would be extended to accept such an object as an argument,
and would add it to the model. (Furiously handwaving whether it
would actually *render* the object, as it is defined in OpenSCAD, or
just pass it through into the CSG tree.)
```

It would be nice if you could take a module defined in the traditional

way, and use it directly in an expression. But that would introduce a

number of problems, and I don't immediately see any real advantages.

On 9/2/2022 5:53 PM, Andy Little via Discuss wrote:
> For now, accessing the member assignments of a module_alias with
> parameters without instantiation into the CSG tree is just a case of
> reusing the same syntax that you can use to access the assignments of
> a module:
>
> module television(size, b) { diagonal = sqrt( size.x^2 + size.y^2);}
>
> |diagonal = module m([30,20]).diagonal; // an anonymous module_alias|
> |m = module (size) television(size, 2); // named alias diagonal1 =
> module m([30,20]).diagonal;|
So I think we're getting at least sort of close to a mutual understanding.
I see a couple of points there where I have trouble.
* Getting the value of "diagonal" requires evaluating the module's
assignments. I can't see doing that unless we also evaluate its
module invocations. (That *does* happen in a couple of obscure
cases in OpenSCAD, but I wouldn't want to make it be a primary
case.) But evaluating the module invocations doesn't necessarily
mean putting the geometry into the model. It could go into a
geometry-as-data structure that might or might not eventually end up
as part of the model.
* I don't think that either "diagonal" or "diagonal1" above require
special syntax, if we have geometry-as-data and a way to peek at the
as-evaluated local variables. m([30,20]) would evaluate the module
with the specified argument, returning some kind of structure that
includes both the as-evaluated local variables and the geometry, and
then you could look at the "diagonal" local variable. (But see below.)
* The middle line, the "m=" line, has only a single module invocation
in it. But what if it had more than one module invocation? What if
it was { television(size); credenza(size); }?
That last one is the hardest.
In any other OpenSCAD context, anywhere that you can have a module
invocation, you can have a { ... } block with any number of assignments
and module invocations. Also, a single module invocation is equivalent
to that same module invocation with braces around it.
That is:
translate([10,0,0]) cube(10);
translate([10,0,0]) { cube(10); }
are equivalent. Similarly:
module box(size) cube(size);
module box(size) { cube(size); }
are equivalent.
So if you can have
m = module (size) television(size);
then you could also have
m = module (size) { television(size); };
and
m = module (size) { television(size); credenza(size); };
and then what would m([30,20]).xxx mean? Would it peek inside
television's local variables, or credenza's? Or the (empty in this
case) local variables for the { ... } block?
And if there's no good answer for that (and I don't think there is), then
m = module (size) { television(size); };
is also in trouble. And if *that's* in trouble, by the equivalence above,
m = module (size) television(size);
is in trouble.
------------------------------------------------------------------------
What I've played with so far is
o = { diagonal = sqrt(16^2 + 9^2); square([16,9]); };
which is *not* a module; it's an expression that evaluates some
assignments and some geometry and returns the result as an object. You
can then say "o.diagonal" and get 18-point-something.
That alone has some interesting effects, because since it is an
expression it can be returned by a function and it can use a function's
arguments in its evaluation:
function television(size) = {
diagonal = sqrt( size.x^2 + size.y^2);
square(size);
};
and then you could talk about television(size).diagonal, which would
evaluate the function, evaluate the object, evaluate the assignment and
the geometry, return "diagonal" and the square, discard the square, and
return "diagonal".
In the discussion above I've concentrated on retrieving the values
from the evaluation, and ignored the geometry. Given o above, or
the television() function, how would you get the geometry added to
the model? So far the best answer seems to be that the render()
module would be extended to accept such an object as an argument,
and would add it to the model. (Furiously handwaving whether it
would actually *render* the object, as it is defined in OpenSCAD, or
just pass it through into the CSG tree.)
It would be nice if you could take a module defined in the traditional
way, and use it directly in an expression. But that would introduce a
number of problems, and I don't immediately see any real advantages.

JB

Jordan Brown

Sat, Sep 3, 2022 3:41 AM

On 9/2/2022 8:33 PM, Jordan Brown wrote:

- Getting the value of "diagonal" requires evaluating the module's

assignments. I can't see doing that unless we also evaluate its

module invocations. (That*does*happen in a couple of obscure

cases in OpenSCAD, but I wouldn't want to make it be a primary case.)

Clarification: when I say "That *does* happen", I mean evaluating a

block's assignments without evaluating its geometry. (That's changed

since 2021.01; kudos if you can identify the case and the change.)

On 9/2/2022 8:33 PM, Jordan Brown wrote:
>
> * Getting the value of "diagonal" requires evaluating the module's
> assignments. I can't see doing that unless we also evaluate its
> module invocations. (That *does* happen in a couple of obscure
> cases in OpenSCAD, but I wouldn't want to make it be a primary case.)
>
Clarification: when I say "That *does* happen", I mean evaluating a
block's assignments without evaluating its geometry. (That's changed
since 2021.01; kudos if you can identify the case and the change.)

K

kwikius@yahoo.com

Sat, Sep 3, 2022 9:52 AM

I think the best thing to do is to try implementing this a little more, to see what is possible and what isnt . So far I have implemented some (most?) ofthe syntax, but not done much on the evaluation.

I hope that some questions are answered by the example linked below

Note that the example is running in the fork executable, but passing syntax only. Evaluation is the next part to do some work on!

```
module television(diagonal, thickness) {
```

```
// Ratio for a wide-screen TV
```

```
nominal_h = 9;
```

```
nominal_w = 16;
```

```
nominal_diagonal = sqrt(nominal_h^2 + nominal_w^2);
```

```
// Multiplier for *this* TV
```

```
ratio = diagonal/nominal_diagonal;
```

```
// Resulting height and width
```

```
h = nominal_h * ratio;
```

```
w = nominal_w * ratio;
```

```
cube([w, thickness, h]);
```

```
// add some feet
```

```
translate([0,0,-1]) cube([1,thickness,1]);
```

```
translate([w-1,0,-1]) cube([1,thickness,1]);
```

```
echo(h=h, w=w, diagonal=diagonal);
```

```
}
```

```
// module_alias to television
```

```
m = module (d) television(d,5);
```

```
ratio = module m(20).ratio;
```

```
// module_alias to anonymous module
```

```
m1 = module (params) { television(params.d, params.t); };
```

```
// module_alias to anonymous module
```

```
m2 = module (params, size) { television(params.d, params.t); credenza(size); };
```

```
// a module alias referring to an anonymous module
```

```
// containing a member module named member
```

```
m3 = module (params, size = [1,2] ) {
```

```
params = params;
```

```
size = size;
```

```
telly = module m2(params,size);
```

```
```

```
cube([size.x,params.d,size.y]);
```

```
module member() {
```

```
c = module cube([1,2,3]);
```

```
x = 1;
```

```
}
```

```
f = function (a,b) a+b;
```

```
};
```

```
m4 = module m3([20,20]);
```

```
diagonal = module m3([1,2]). module telly.diagonal;
```

```
telly = module m3([1,2]). module telly;
```

```
telly();
```

```
x1 = module m3([1,2]). module member.x;
```

```
c_x = module m3([1,2,3]). module member.c.x;
```

```
m3_member = module m3([1,2]). module member();
```

```
m3_member3 = module m3([1,2]). module member;
```

```
m4_size = module m4().size;
```

```
m4_sizex = module m4.size.x;
```

I think the best thing to do is to try implementing this a little more, to see what is possible and what isnt . So far I have implemented some (most?) ofthe syntax, but not done much on the evaluation.
I hope that some questions are answered by the example linked below
https://github.com/kwikius/openscad/blob/WIP-first-class-module/tests/data/scad/experimental/first_class_module/first_class2.scad
Note that the example is running in the fork executable, but passing syntax only. Evaluation is the next part to do some work on!
```
module television(diagonal, thickness) {
```
```
// Ratio for a wide-screen TV
```
```
nominal_h = 9;
```
```
nominal_w = 16;
```
```
nominal_diagonal = sqrt(nominal_h^2 + nominal_w^2);
```
```
// Multiplier for *this* TV
```
```
ratio = diagonal/nominal_diagonal;
```
```
// Resulting height and width
```
```
h = nominal_h * ratio;
```
```
w = nominal_w * ratio;
```
```
cube([w, thickness, h]);
```
```
// add some feet
```
```
translate([0,0,-1]) cube([1,thickness,1]);
```
```
translate([w-1,0,-1]) cube([1,thickness,1]);
```
```
echo(h=h, w=w, diagonal=diagonal);
```
```
}
```
```
// module_alias to television
```
```
m = module (d) television(d,5);
```
```
ratio = module m(20).ratio;
```
```
// module_alias to anonymous module
```
```
m1 = module (params) { television(params.d, params.t); };
```
```
// module_alias to anonymous module
```
```
m2 = module (params, size) { television(params.d, params.t); credenza(size); };
```
```
// a module alias referring to an anonymous module
```
```
// containing a member module named member
```
```
m3 = module (params, size = [1,2] ) {
```
```
params = params;
```
```
size = size;
```
```
telly = module m2(params,size);
```
```
```
```
cube([size.x,params.d,size.y]);
```
```
module member() {
```
```
c = module cube([1,2,3]);
```
```
x = 1;
```
```
}
```
```
f = function (a,b) a+b;
```
```
};
```
```
m4 = module m3([20,20]);
```
```
diagonal = module m3([1,2]). module telly.diagonal;
```
```
telly = module m3([1,2]). module telly;
```
```
telly();
```
```
x1 = module m3([1,2]). module member.x;
```
```
c_x = module m3([1,2,3]). module member.c.x;
```
```
m3_member = module m3([1,2]). module member();
```
```
m3_member3 = module m3([1,2]). module member;
```
```
m4_size = module m4().size;
```
```
m4_sizex = module m4.size.x;
```

Replying to:

Empathy v1.0
2022 ©Harmonylists.com