Classes

Scenome Scripting Language supports simple, user-defined classes. The goal of these classes is to promote encapsulation in Scenome Scripting Language, in order to simplify the development process. For example: passing a single object to a function instead of a long list of separate function parameters. Later, you can change the data members in the class without having to add another function parameter, which means you won't have to go update all your call sites. In this way, Scenome Scripting Language classes are like structs in the C language.

Details

Details are as follows:

Examples

Several examples are provided below.

The following example illustrates class declaration and initialization:

// Declare a new class.
class Inputs
{
   string m_sName;
   auto Float32Vector m_vPosition;
};
auto Inputs data;
data.m_sName = "Test";
data.m_vPosition.X = 0.0;
data.m_vPosition.Y = 0.0;
data.m_vPosition.Z = 0.0;

The following example illustrates passing a class object to a function.

// Declare the class in a file called input.ssl.
class Inputs
{
   string m_sName;
   auto Float32Vector m_vPosition;
};
//  Implement the initialization function in inputs.ssl.
function int Initialize( Inputs p_oData )
{
   if( !( p_oData ) )
   {
      return 0;
   }

   p_oData.m_sName = "Test";
   p_oData.m_vPosition.X = 0.0;
   p_oData.m_vPosition.Y = 0.0;
   p_oData.m_vPosition.Z = 0.0;

   return 1;
}

//  Call the initialization function.
function int Create()
{
   auto Inputs data;
   return Initialize( data );
}

The following example illustrates late initialization of data members:

// Declare a new class.
class Inputs
{
   string m_sName;            // Automatically initialized to an empty string.
   int m_iCount;              // Automatically zero initialized.
   double m_dPrecision;       // Automatically zero initialized.
   auto Float32Vector m_vSrc; // Initialized to C++ constructor or data interface defaults.
   Float32Vector m_vDst;      // Initialized to nullptr.
};
auto Inputs data;
data.m_sName = "Test";
data.m_vSrc.X = 0.0;
data.m_vSrc.Y = 0.0;
data.m_vSrc.Z = 0.0;

// Late initialize...
auto Float32Vector a_vDst;
a_vDst.X = 1.0;
a_vDst.Y = 1.0;
a_vDst.Z = 1.0;

//data.m_vDst.X = 1.0; // This would generate a script nullptr error since data.m_vDst is still a nullptr...

data.m_vDst = a_vDst; // Here we initialize data.m_vDst...

data.m_vDst.X = 1.0; // Totally fine...

The following example illustrates nested classes:

// Declare a new class.
class Positions
{
   auto Float32Vector m_vSrc;
   auto Float32Vector m_vDst;
};

class Inputs
{
   string m_sName;
   Positions m_oPositions;
};
auto Inputs data;
data.m_sName = "Test";
data.m_oPositions.m_vSrc.X = 0.0;
data.m_oPositions.m_vSrc.Y = 0.0;
data.m_oPositions.m_vSrc.Z = 0.0;

Class objects can be stored in <TypeBuffer> objects. While not strictly equivalent to arrays of class objects, it's still very useful.

// Declare a new class.
class Positions
{
   auto Float32Vector m_vSrc;
   auto Float32Vector m_vDst;
};
auto Positions a;
auto Positions b;

auto TypeBuffer a_apStorage;
a_apStorage.Refers( a );
a_apStorage.Refers( b );

// Or...
Positions c = new Positions;
Positions d = new Positions;

auto TypeBuffer a_apStorage;
a_apStorage.Owns( c ); // Object c is destroyed when a_apStorage goes out of scope...
a_apStorage.Owns( d ); // Object d is destroyed when a_apStorage goes out of scope...

The following example illustrates memory management:

// Declare a new class.
class Inputs
{
   string m_sName;
   auto Float32Vector m_vSrc;
   Float32Vector m_vDst;
};
{
   auto Inputs data;
   data.m_sName = "Test";
   data.m_vSrc.X = 0.0;
   data.m_vSrc.Y = 0.0;
   data.m_vSrc.Z = 0.0;

   // Late initialize using new... Except for cases where
   // using new is absolutely required, we don't recommend
   // doing this... so for classes in Scenome Scripting Language,
   // we recommend "almost always auto".
   Float32Vector a_vDst = new Float32Vector( 1.0, 1.0, 1.0, 1.0 );
   data.m_vDst = a_vDst;

   // Since it's declared with auto, data.m_vSrc will be automatically
   // destroyed at end of scope. We don't have to do anything.

   // We must still manually delete m_vDst;
   data.m_vDst = null;
   delete a_vDst;

   // End of scope...
}