OpenSCAD User Manual/Objects

part of the section on Values, Data Types, and Constants

Creating Objects

Built-In Object Creators

textmetrics()
function to extract size and formatting info from a text string.
fontmetrics()
function to extract information from a font.
data=import()
function to import data from a JSON file.

Object() Function

[Note: Requires version Dev Snapshot 2025.07.11 or later]

Note: Objects are currently experimental and so must be enabled in menu item Edit > Preferences > Features Tab > checkbox

A call to the object() function returns an object containing the member definitions in the order they are given as arguments to the function call.

Member Names

Member names are strings and are not limited by the rules for variable names.

unicode_name="invalid\u00A3object,name";
namevar = "goodname";
xxx= object( [ 
     ["bad name", 12],
     [unicode_name,"anything"],
     [goodname,5],
     ["this\nthat", "value" ]
     ]
     );

which echo shows as:

{ bad name = 12; invalid£object,name = "anything"; goodname = "5"; this
that = "value"; }

Note the Unicode character "£" and the newline between "this" and "that".

Members can be accessed for use in expressions in two ways, as will be seen later in this page. Member names that follow the Variable Name rules may use Dot Notation in an expression:

sphere( r=xxx.goodname);

in the same way as the first three elements of a vector may be access by vec.x, vec.y, and vec.z.

All member names may use the square brackets and string syntax for accessing object members:

sphere( r=xxx["bad name"]);

which in this case is a constant string, "bad name", with a space character in it, so a member reference in dot notation, as xxx.bad name, will emit a warning.

The string between square brackets may be a constant, a variable with a string value, or a string resulting from an expressions evaluation.

Name=Value Members

The simplest member definition is a <name>=<value> assignment, where name is a valid variable name and <value> is an expression result.

Example

Fred = object( name="Fred", spouse="Wilma", friends=["Barney"] );
// ECHO: Fred = { name = "Fred"; spouse = "Wilma"; friend = ["Barney"]; }

When <value> is calculated by an expression that results in undef the member is still added:

Barney = object( name="Barney", spouse=Betty );
// ECHO: Barney = { name = "Barney"; spouse = undef; }

Vector of Members

Members may also be created using a vector of [name,value] vector elements

my_object = object( [ ["<name>",<value>], ["<name>",<value>]  ] );

Where the <name> is any expression resulting in a string, and the value is any expression result.

Using the vector argument form of member definition it is possible to edit an object's members. A name only element like, [["name"]], will remove the named member from the object. It is not an error to attempt removing a member that does not exist in the object.

Assigning undef is allowed, as seen above, but that does not remove the member.

Example of Removal

We define a person:

Fred = object( name="Fred", spouse="Wilma", friends=["Barney"] );

and then another one:

Wilma= object( name="Wilma", spouse=Fred, friends=["Betty"] );

but for Wilma the object Fred has been assigned as the spouse. Now that the Wilma object is defined a copy of Fred could be made using the Wilma object as spouse. First we copy the members of Fred to newFred, remove the spouse member, and then define a new spouse using the object Wilma:

newFred = object( Fred, [["spouse"]], spouse=Wilma );
echo( newFred );
//ECHO: { name = "Fred"; friends = ["barney"]; spouse={ name="Wilma"; ... }}

The spouse member is gone.

Removing a member that does not exist in the object is not an error:

newFred = object( Fred, [["child"]] );

newFred is an exact copy of Fred as there was no "child" member to remove.

Copying an Object

An existing object may be given as an argument to an object():

o1 = object( one=1 ); // make an object
o2 = object( o1 );      // make a copy

Additional members may be added to the copy, and removals done, as in the previous section.

Lets assume that Fred and Wilma objects are already defined. Wilma with a member spouse=Fred and having removed spouse from Fred we want to add the Wilma object as spouse:

newFred = object( Fred, spouse=Wilma );

and now:

newFred = { 
  name = "Fred";
  spouse = {
    name = "Wilma"; // object as spouse
    spouse = { 
      name = "Fred"; // the Fred Object is Wilma's spouse
      spouse = "wilma"; // placeholder value
      friends = ["barney"]; // Fred's friend
      };
  friends = ["Betty"]; // Wilma's friend
  };
 friends = ["barney"]; // newFred's friend
 }

Now we can chain member references ject in an object:

echo( WHsp = Wilma.spouse.spouse, "\n" ); // "wilma" from original Fred

Note: The Wilma.spouse is the original Fred and newFred has the Wilma object as spouse

The argument list of object() may combine any of the member definition forms allowing us to combine operations. The spouse member could be removed and replaced in one call:

newFred = object( Fred, [["spouse"]], spouse=Wilma );
echo( newFred =newFred, "\n");

gives

newFred = { 
  name = "Fred";
  friends = ["barney"];
  spouse = { name = "Wilma"; spouse = undef; friends = ["Betty"]; };
  }, 

Showing the spouse member is now the Wilma object and is the last member in the object.

Note: The order of the members is updated by the removal a member and by the addition of a new one

Object Combinations Accumulate

Giving an object as an argument copies its members to the new object. Giving additional objects as arguments will add its members to the new object, overriding any members of the first object that have the same name.

The language rule about assigning a new value to an existing variable applies to object creation. The rule is that assignment to a previously defined name sets the new value at the location of the first definition meaning that the new value is used everywhere in the script. The arguments to object() are effectively a sequence of assignments creating named objects and so any of the member definition forms that use existing member names will override previous values, and when listed ( by echo() ) will show the last set value in the position of the first definition.

When we add two objects to create xxx:

Fred = object( name="Fred", spouse="wilma", friends=["Barney"] );
echo(Fred =Fred, "\n");
   // define Wilma using the Fred object as spouse
Wilma = object( name="Wilma", spouse=Fred, friends=["Betty"] );
echo( Wilma=Wilma, "\n");
xxx=object(Fred,Wilma);

The combined object, xxx, will be a copy of Wilma:

Fred = { name = "Fred"; spouse = "wilma"; friends = ["Barney"]; }
Wilma = { name = "Wilma"; 
    spouse = { name = "Fred"; spouse = "wilma"; friends = ["Barney"]; };
    friends = ["Betty"];
    }
ECHO: { name = "Wilma"; 
    spouse = { name = "Fred"; spouse = "wilma"; friends = ["Barney"]; };
    friends = ["Betty"];
    }

When the object being combined have members that are not in the others they are added to the combination in the order of the list:

Fred = object( name="Fred", spouse="wilma", children=["Pebbles"] );
Wilma = object( name="Wilma", spouse=Fred, pets=["Dino"] );
xxx=object(Fred,Wilma);
echo(xxx);

The combined result, xxx, is thus:

 { name = "Wilma";
   spouse = { name = "Fred"; spouse = "wilma"; children = ["Pebbles"]; };
   children = ["Pebbles"];
   pets = ["Dino"];
 }

Members name and spouse from Wilma have overridden those of Fred, and the children and pets vectors are added in the order of Fred and Wilma in the argument list.

To illustrate this further we combine the original Fred and Wilma, then remove the spouse member:

 xxx = object( Fred, Wilma, <nowiki>[["spouse"]]</nowiki> );
 // xxx= { name = "Wilma"; friend = ["Betty"]; }

Explanation:

  1. Fred object is added to xxx
  2. members of the Wilma object override the values of Fred's members
  3. removing the spouse member affects the copy of Wilma
  4. xxx is a copy of Wilma, with no spouse

If an assignment or object later in the argument list overrides something before it it may look like members are out of order. If we prefer to have Fred.spouse be the Wilma object we might try:

   // set spouse to a placeholder value
 Fred = object( name="Fred", spouse="wilma", friends=["barney"] );
   // create a Wilma object
 Wilma = object( name="Wilma", spouse=Fred, friends=["Betty"] );
 // this will NOT give Fred2 the Wilma object as spouse
 Fred2 = object( spouse=Wilma, Fred );
 // ECHO: { spouse = "wilma"; name = "Fred"; friends = ["barney"]; }

To explain:

  1. The new object, Fred2, is given the Wilma object as its first member, spouse
  2. the Fred object is added so its members are applied:
    1. Fred.spouse ("wilma") overrides Fred2.spouse in the position of the first definition in Fred2
    2. Fred.name and Fred.friends are added to Fred2 as second and third members

The result shown by echo() by the rule of "new value defined as if at original definition" is correct.

Functions as Members

fx = function(x)x+2;
xxx=object( this="that",that=12, func=function(x)x+2);
echo(xxx, xxx.func(8) );
// ECHO: { this = "that"; that = 12; func = function(x) (x + 2); }, 10

Object Data Type

[Note: Requires version Development snapshot]

An "object" is a collection of names and associated values. In other languages this data structure might be called an object (JavaScript), a dictionary (Python), or an associative array (some UNIX shells, awk),

Retrieving Member Values

The name of a member may be used in this dot notation:

n = obj.name;

Using the vector index form, but with a string required in place of an integer, we can achieve the same result:

n=obj["name"];

Members with valid identifier names can be accessed using either syntax. Names for members that do not meet the Named Object rules must be given as strings using this format.

Iterating over object members

The for statement is extended to loop through the keys of an object in the order the object members were defined in:

 for( key = object ) <statement object[key]>

The loop counter key in this case, is the member's name as a string. Inside the loop the array index form, ["key"], must be used to refer to members, with the advantage that even keys with non-compliant names will be correctly processed.

So:

oo = object( [["a!",1],["b@",2],["c#",3],["d$",4],["e%",5],["f^",6] ] );
keys = [for( io = oo ) io]; //  ["a!", "b@", "c#", "d$", "e%", "f^"]

To be able to process all of the object's values we must use the text names:

doubles = object( [ for( io = oo ) [ io, oo[io] * 2 ] ] );
echo(doubles);  // [2, 4, 6, 8, 10, 12]

Object Comparisons

The equality operators work with objects:

my_object = object( name=12 );
your_object = object( my_object ); // make a copy
echo( my_object == your_object);   // true
echo( my_object != your_object);   // false

an_object = object( name="this", other=12 );
na_object = object( other=12, name="this" );
echo( an_object == na_object);     // false
echo( an_object != na_object);     // true

But not the relational ones:

xx_object = object( name="this", other=12 );
yy_object = object( name="this", other=13 );

echo( xx_object <  yy_object ); // WARNING: operation undefined (object < object) 
echo( xx_object >= yy_object ); // WARNING: operation undefined (object >= object)


is_object() Function

returns true when its argument is an object and false otherwise.

has_key() Function

There is a new function has_key( <object>,<name> ) that returns true if the object contains the named key.