Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

REOPENED Can't override include variables #289

Closed
MichaelAtOz opened this Issue · 27 comments

3 participants

@MichaelAtOz

While using the Write.scad library, I wanted to change the 't' variable defined in the library by setting it to another variable. I had issues, so I reproduced it in this simple code.

testlib.scad

i=1;

test.scad

include <testlib.scad>      // only has i=1
echo(str(version()));
j=3;
echo("Step 1, i=",i,",j=",j);

/*
 * uncomment step 2 and i becomes undef
 */

/*
// Step 2
i=j;
echo("Step 2, i=",i,",j=",j);
*/

Is this intended?

This was also in conjunction with Thingiverse Customisation too, I couldn't use 't' as the customisation variable either, I don't know whether it passes command-line variables or inserts assignment statements inline to override.

@MichaelAtOz MichaelAtOz closed this
@MichaelAtOz MichaelAtOz reopened this
@MichaelAtOz

ps version() = ECHO: "[2013, 1, 8]"

@nophead

An openscad variable only has one value during the life of the program. When there are multiple assignments it takes the last value, but assigns when the variable is first created. At that point (in testlib.scad) "j" is not defined so it does not work.

Whether it is a bug or a feature, I don't know. There was a discussion about it recently in the mailing list.

@MichaelAtOz

I moved J=3 above the include and then I=3. Matches what you describe. I'll add words to the wiki. Counter intuitive as it is.

@MichaelAtOz

Updated wiki. closing.

@MichaelAtOz MichaelAtOz closed this
@MichaelAtOz MichaelAtOz reopened this
@MichaelAtOz

Reopened. Something is wrong with includes/use I think.

I was fiddling with MCAD\gridbeam.scad.

Initially I used 'use' and it produced a nice 1.5inch zBeam. I then though I wanted a smaller beam, so looked at the variables in the library. It then occurred to me that 'use', as I understood it from the wiki "imports modules and functions, but does not execute any commands other than those definitions", so where was the 1.5inch size coming from?
So I added an echo to zBeam() in the library. And a test program;

    $beam_width=10;    // #1
    use <MCAD\gridbeam.scad>
    //$beam_width=10; // #2
    echo("A:$beam_width=",$beam_width);
    zBeam(3);
    echo("B:$beam_width=",$beam_width);

Produces;

    ECHO: "A:$beam_width=", 10
    ECHO: "GB:$beam_width=", 38.1 (ie 1.5 * inch)
    ECHO: "B:$beam_width=", 10

(swapping the #1 & #2 comments on the two assignments doesn't change results)

It seems the variables in the 'use'd library are local private variables and the assign statements in the library are actually executed (as are the 'includes's in the library - where it gets inch from); plus the description of variable handling (the last value is used for the whole program) is inaccurate.

So with 'use' library variables cannot be overridden.

Change 'use' to 'include' and things are different.

With #1 uncommented #2 commented, all three echo's return undef. Other way they all return 10.

I can see why the latter, but the former should, according to described behaviour, be 38.1 not undef.

Also with 'use' processing library 'includes', while maybe handy, it won't let you do some other creative stuff, for example including your own version of units.scad ie

include <myunits.scad>   
use <gridbeam.scad>
zBeam(2); // now based on my units

So can someone who understands the intent of 'use' v's 'include' describe whether that is intended outcome. I can see how the observed 'use' behaviour may be useful in some circumstances, but not being able to override variables assigned in the library is not expected behaviour, or useful.

@MichaelAtOz

p.s. and is a '$' prefixed variable any different to normal variables?

@MichaelAtOz

It's even stranger

//$beam_width=10;                       // #1
include <MCAD\gridbeam.scad>
/*
$beam_width=10;                         // #2
$beam_hole_radius = inch * 5/16;
$beam_is_hollow = 1;
$beam_wall_thickness = inch * 1/8;
$beam_shelf_thickness = inch * 1/4;
*/
echo("A:$beam_width=",$beam_width,"$beam_hole_radius=",$beam_hole_radius,"$beam_is_hollow=",$beam_is_hollow);
echo("A:$beam_wall_thickness=",$beam_wall_thickness,"$beam_shelf_thickness=",$beam_shelf_thickness);

zBeam(3);
echo("B:$beam_width=",$beam_width,"$beam_hole_radius=",$beam_hole_radius,"$beam_is_hollow=",$beam_is_hollow);
echo("B:$beam_wall_thickness=",$beam_wall_thickness,"$beam_shelf_thickness=",$beam_shelf_thickness);

As above, with the variables commented out, it produces a 3 segment gridbream at default 1.5inch.

However remove the block comment at #2 and NO OBJECT is produced!
The echo GB:$beam_width... I added to zBeam() is executed; ie

Module cache size: 2 modules
Compiling design (CSG Tree generation)...
ECHO: "A:$beam_width=", 10, "$beam_hole_radius=", 7.9375, "$beam_is_hollow=", 1
ECHO: "A:$beam_wall_thickness=", 3.175, "$beam_shelf_thickness=", 6.35
ECHO: "GB:$beam_width=", 10     <--added in zBeam()
ECHO: "B:$beam_width=", 10, "$beam_hole_radius=", 7.9375, "$beam_is_hollow=", 1
ECHO: "B:$beam_wall_thickness=", 3.175, "$beam_shelf_thickness=", 6.35
Compiling design (CSG Products generation)...
PolySets in cache: 18
PolySet cache size in bytes: 28728
CGAL Polyhedrons in cache: 0
CGAL cache size in bytes: 0
Compiling design (CSG Products normalization)...
Normalized CSG tree has 8 elements
CSG generation finished.
@MichaelAtOz

Seems $ prefixed variables are handled differently, for a start they don't generate "WARNING: Ignoring unknown variable".

@MichaelAtOz

Further strangeness

$beam_width=10;                         // #1
include <MCAD\gridbeam.scad>
echo("A:$beam_width=",$beam_width);
zBeam(3);
echo("B:$beam_width=",$beam_width);

Produces output below & NO OBJECT (as potentially expected), but what's with unknown variable 'inch'?

Module cache size: 2 modules
Compiling design (CSG Tree generation)...
WARNING: Ignoring unknown variable 'inch'.
ECHO: "A:$beam_width=", undef
ECHO: "GB:$beam_width=", undef
ECHO: "B:$beam_width=", undef
Compiling design (CSG Products generation)...
PolySets in cache: 18
PolySet cache size in bytes: 28728
CGAL Polyhedrons in cache: 0
CGAL cache size in bytes: 0
Compiling design (CSG Products normalization)...
Normalized CSG tree has 7 elements
CSG generation finished.

So the variable at #1 is causing the "include <units.scad>" to not occur, possibly other effects.

Anyway - something is wrong.

@kintel
Owner

I'll look into this.
Just one quick observation: The gridbeam library doesn't produce useful beam for $beam_width < 17, and will produce an empty object for $beam_width < 12

@MichaelAtOz

OK, I suspect there may have been some side effect with Command-Line arguments "In order to pre-define variables, use the -D option. It can be given repeatedly. Each occurrence of -D must be followed by an assignment. Unlike normal OpenSCAD assignments, these assignments don't define variables, but constants, which can not be changed inside the program, and can thus be used to overwrite values defined in the program at export time"

@kintel
Owner

-D cmd-line arguments can actually be any OpenSCAD statements. They are just automatically appended at the end of your main source file. i.e., if they are assignments (e.g. openscad -Dmyvar=3), it's equivalent to defining a top-level myvar=3; in your code.

@kintel
Owner

To clarify your question about the difference between $ variables and normal variables:
$ variables are meant as internal, special variables. It's not recommended to define your own, but if you do, this is how it works (today):

1) As you pointed out, warnings are suppressed when searching for unknown $ variables
2) Also, variables are searched for in all parent scopes, meaning that they are inherited downwards into modules. Normal variables are only visible in the scope where they are defined (typically a file) and if you want to pass variables down, you send them as parameters to modules.

Since $ variables are meant as internal variables, we don't support "fancy" behavior as calculating the value of a $ variable based on values of variables in some child scope. This is the reason you get the "unknown variable 'inch'" message. Instead of trying to fix this, I would rather look into redefining variable scoping properly in a future version of OpenSCAD, and for now, avoid using custom defined $ variables.

I actually hadn't noticed that this library used such variables until now - perhaps this should be cleaned up to avoid more confusion..

I suspect that your remaining issues are freak-conditions related to all this. Removing the use of $ variables should clear up most of it. If you still have issues after, that, I'd be happy to continue this :)

@MichaelAtOz

I changed gridbeam to remove all the $'s.

Two things.

1

Still strange the "unknown variable inch" happens if I have it as below

beam_width=10;                          // #1
include <MCAD\gridbeamTest.scad>
//beam_width=10;                            // #2
beam_hole_radius = 4;
beam_is_hollow = 1;
beam_wall_thickness = 2;
beam_shelf_thickness = 4;

echo("A:beam_width=",beam_width);
zBeam(3);
echo("B:beam_width=",beam_width);

Produces

Module cache size: 3 modules
Compiling design (CSG Tree generation)...
WARNING: Ignoring unknown variable 'inch'.
ECHO: "A:beam_width=", undef
ECHO: "GB:beam_width=", undef
ECHO: "B:beam_width=", undef
Compiling design (CSG Products generation)...
PolySets in cache: 54
PolySet cache size in bytes: 162304
CGAL Polyhedrons in cache: 0
CGAL cache size in bytes: 0
Compiling design (CSG Products normalization)...
Normalized CSG tree has 7 elements
CSG generation finished.

I would expect beam_width to be 38.1 not undef. So is it the beam_width = inch * 1.5; is evaluated (as it is the last assign), but at the root program level where inch is undefined. Meaning the include <units.scad> within the first include is not actually included?? ie sub-level includes are local.

Swapping #1 #2 comments works as intended.

2

The other issue where you can't override 'use' variable still occurs, ie

//beam_width=10;                            // #1
use <MCAD\gridbeamTest.scad>
beam_width=10;                          // #2
beam_hole_radius = 4;
beam_is_hollow = 1;
beam_wall_thickness = 2;
beam_shelf_thickness = 4;

echo("A:beam_width=",beam_width);
zBeam(3);
echo("B:beam_width=",beam_width);

Produces a 38.1mm beam

Module cache size: 3 modules
Compiling design (CSG Tree generation)...
ECHO: "A:beam_width=", 10
ECHO: "GB:beam_width=", 38.1
ECHO: "B:beam_width=", 10
Compiling design (CSG Products generation)...
PolySets in cache: 56
PolySet cache size in bytes: 168296
CGAL Polyhedrons in cache: 0
CGAL cache size in bytes: 0
Compiling design (CSG Products normalization)...
Normalized CSG tree has 8 elements
CSG generation finished.

So the zBeam() is not inheriting beam_width, but is using the value from beam_width = inch * 1.5; from the library, which in-turn means the 'use' does process the assignments and the "include <units.scad>", but only locally to the library. This means the assign is evaluated twice, one in scope of the 'use' and then at the root.

As described(*) I would expect non module/function code in the 'use' file to have zero effect, and thus the beam_width would be inherited.

AAh commenting out beam_width in the library produces unknown variable. I think I see it now, but don't think it is good.

I'll mull this over and attempt to write it up for others & the wiki.

*
"use <filename> imports modules and functions, but does not execute any commands other than those definitions" &
"For instance, if you set up your shared library files to have default values defined as variables at their root level, when you include that file in your own code, you can 're-define' or override those constants by simply assigning a new value to them"

@kintel
Owner

Thanks for the patient testing.
I agree that something is a bit puzzling - I will look over this in more detail within the next few days.

@MichaelAtOz

Additional info for case 1 above, I added inch to the echo (root level) and it output 25.4, so the sub-level include is included, question is then where is the 'unknown inch'. Also when I changed beam_width = inch * 1.5;, in the library, to just =20 the unknown error stopped, so it is that line which is causing the unknown.

@kintel
Owner

I'm working on a fix for the "unknown variable inch" problem. Are you able to recompile OpenSCAD yourself? If not, which platform are you on?

@MichaelAtOz

No can't compile. Windows 7/64, but obviously running it as x86.

@kintel
Owner

Here's a minimal example which should trigger this issue:

myval = 2;
i = 2;
myval = i * 2;
echo(myval);

After the fix, it echoes 4, without any warnings.
It's been tested on Mac and Linux. I'll check if someone can upload a Windows build.

@kintel
Owner

Regarding overriding variables: Variables in a USE'd file are hidden and you cannot override them. When writing a library with configurable parts, pass these as parameters to modules.

If you want to change something, you can fall back to include. This will work:

include <MCAD/gridbeam.scad>
beam_width=30;
zBeam(3);

I believe I've addressed all your issues. When you get a change to test the new version, please close this issue unless you're still having issues.

@MichaelAtOz
@MichaelAtOz

Is this included in 2013 03 09? If so it didn't fix the unknown variable, so I'm assuming not.

@kintel
Owner

Unfortunately not - it was fixed in 2013.03.11.
I'll request new binaries once the current patches are cleaned up.

@kintel
Owner

MichaelAtOz: Windows binaries should be up by now - can I close this?

@MichaelAtOz

Marius your minimal case

myval = 2;
i = 2;
myval = i * 2;
echo(myval);

Works. Ok to close.

While looking at my gridbeam stuff from above, I came across another error, different topic, will check it is not reported and raise an issue.

I'll think about revamping gridbeam as parametric & get rid of the $variables.

@MichaelAtOz

My bug mentioned above may be a similar artefact of issue #181, basically if a library does not exist when you load your scad file, you get an error, create the library, reload & OpenSCAD still says library does not exist.

Do you want this as a separate issue with a name reflecting the issue (rather than autoreload too quick) or just add details to issue #181?

@kintel
Owner

Please create a new issue - I've heard about that multiple times, but never really managed to reproduce it properly, so it would be cool if you could very carefully craft a recipe on how to reproduce it.

@kintel kintel closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.