Data Members

Quick reference

data-member1 = [expression] data-name
data-name2 = @’ | ‘@@variable-name
variable-name = name-predicate
name-predicate3 = instance-name [’?’]
instance-name = lowercase {alphanumeric}

Both class instances (particular instantiations of classes or simply “objects”) and classes (object types) can have members that store data.

Instance data members start with @ and class data members start with @@.

Here is a mental aid to differentiate them:

  • temporary variables are all at the current scope and do not need any @:
    param1, obj, list
  • instance data is one level deep, so use one @:
    vector.@x, guy.@hit_points, @member_data
  • class data is two levels deep, so use two @@:
    BadGuy.@@hit_points_max, @@random, @@class_data

So why @ and @@?

Backgrounder from Conan Reis)_br/>
Being able to visually differentiate data members, class data members and temporary variables (including parameter names from routines) from each other can be really useful. It is possible to have the IDE highlight these different categories of variables with different colors, fonts, etc. though we often cut and paste code outside the IDE which would not have this highlighting. Visually differentiating variables also helps reduce name collisions.

For many years I worked on projects that simply used naming conventions for data members. Since the naming was never _enforced
by the compiler, people broke the convention all the time. Even worse, frequently enough a naming convention was used in the wrong circumstance such as making it seem that a class data member was actually an instance data member or vice versa.

The solution is to have the compiler enforce a naming convention.

In my experience, people dislike enforced naming conventions if they are particular letters whereas they seem to more readily accept enforced symbol use.

(I also did not want to enforce a full word in their declaration like static. The creator of C++, Bjarne Stroustrup, used static because he didn’t want to introduce another reserved word. He later regretted it since it muddied the usage of static in other areas and it was an arbitrary word for the concept and not using conventional object-oriented terminology.)

So which symbols?

SkookumScript already used @ for its scope resolution operator for routines. (The equivalent in C++ is ::.) This is generally only used when you want to call an overridden version of a superclass routine from a subclass. So if you are in the do_stuff method in ClassB and you want to call the do_stuff method from ClassA you call it with ClassA@do_stuff.

The @ symbol also has the nice connotation that it is called “at”. So ClassA@do_stuff is read as “Class A at do stuff”. Otherwise do_stuff without the scope resolution operator will recursively call itself.
The “at” aspect of @ makes a lot of sense so I thought about using @ for data members.

I don’t like to arbitrarily choose syntax when there is a lot of language history and convention to choose from - even if it may not seem like it at times in SkookumScript. Of course it occurred to me that Ruby also used @ and @@ for its enforced data member naming convention. So I went with that since there is some history to draw on and people in the Ruby community seemed to like it.

So that is how SkookumScript ended up using @ and @@ for data members.

Instance Data

All data members for a class instance (“class instance data members” or just “data members” or “instance data”) must start with a single “at” symbol @. For example, particular Enemy objects (such as bad_bart and mean_mimi) could store the current hit points in a data member called @hit_points or more fully bad_bart.@hit_points, mean_mimi.@hit_points

Any instance data members are declared in a ! file and they need to be bound to an object when an object instance constructor is called. Constructors start with an ! and their files are named !().sk or !ctor_name().sk. After the instance data is initialized in a constructor you can access them in other SkookumScript code as needed. The files and their names are managed automatically for you by the SkookumIDE.

Class data

All data members for a class (“class data members” or just “class data”) must start with two “at” symbols @@. For example, a maximum amount of hit points for any Enemy class could be called @@hit_point_max or more fully Enemy.@@hit_point_max.

Note that class instance objects may also access class data members so mean_mimi.@@hit_point_max is also valid.

Any class data members are declared in a ! file and they need to be bound to an object when the class constructor is called. Class constructors are named ! and their files are named !() The C in the files indicate that it is for a whole class and not an instance of a class. After the class data is initialized in a class constructor you can access them in other SkookumScript code as needed. Again, the files and their names are managed automatically for you by the SkookumIDE.

Setting up new data members

To create new data members you must declare them and initialize them in a constructor.

The best way to add a new data member is to use the “Add a Class/Member” widget in the SkookumIDE. It is located at the bottom of the “Members” window.

SkookumIDE class highlighting

To bring it up, you first click on the class that you want to add a data member to on the class hierarchy (the “classes” window). Then open up the “Add a Class/Member” widget. There are many ways to do this:

To open up the You can do this by going to “File” menu and select “Add a Class/Member”, or click on the “Add a Class/Member” pane that is at the bottom of the “Members” tab or just press Ctrl+N (for New).

Since this is the first time you are adding SkookumScript code into your project you will see the following:

SkookumIDE confirm Skookify?

Once you select “OK” the files SkookumScript needs will be added to your project. We call this Skookifying your project and once done your project is Skookified.

Now you have access to the “Add a Class\Member” dialog.

Comparision: C++ Data members

Instance data members starting with @ in SkookumScript are similar to C++ non-static members. C++ non-static data members often have a naming convention such as start with m_ for member. Though again these are just conventions and not enforced by the compiler.

Class data members starting with @@ in SkookumScript are similar to C++ static data members. C++ static data members often have a naming convention such as start with ms_ for member static. Though these are just conventions and not enforced by the compiler.

Data member declaration

data-filename4 = !Data’ [‘C’] ‘.skoo
data-file = ws [data-definition {wsr data-definition} ws]
data-definition5 = {annotation ws} [class-desc wsr] ‘!data-name
annotation6 = &instance-name

Data members must be declared and have their class type specified for a whole class. Multiple data members are declared in the same ! (for instance data) or ! (for class data)

You can see the data member file definition for both class and instance data members in the SkookumScript syntax.

  • [expand these out]
  • setting type in data file
  • predicates ending with ?
  • unlike temporary variables can only switch to types that are same or subclass of type specified in data file
  • raw annotations
  • access and data hiding

Initialization in constructors

After data members have been declared they need to bind : to an initial object. This is called data member initialization. It is condsidered to be an error if all the data members are not bound by the end of a constructor. If an initial object is not bound to a data member in its appropriate constructor then it is automatically bound to the nil object - so at least it is bound to something.

For example, the body of the class constructor !()

Using data members in code

Give examples of using data members…

Binding objects and type inference

Since data members can be used in different routines, it is not possible for the SkookumScript parser to infer their class type if it changes just by looking at a particular routine. Data members could be bound : to one object type in one routine and a different routine could concurrently change the object type without the parser knowing.

This means that as far as the Parser is concerned the only class type that a data member can be is the type that is specified when it is declared (in its ! or ! file). The parser restricts rebinding of a data member to object types that are of the same type or a subclass of the type in its declaration.

Note that temporary variables and parameter variables within a routine or an arbitrary code snippet can have their types inferred by the SkookumScript parser – all the context is within the one file for the parser to see where and when variables are bound to particular types of objects.

Special considerations for raw data members

Data members that have the raw annotation in their declaration allow non-SkookumScript values created by the runtime (such as Unreal Engine Blueprint variables) to be treated as if they were SkookumScript data members. This is for convienience and asthetics – they are more like accessor method calls behind the scenes.

Because they are not true SkookumScript data members they have a few restrictions:

  • restriction1
  • restriction2
  1. Optional expression can be used to access data member from an object – if omitted, this is inferred.

  2. @’ indicates instance data member and ‘@@’ indicates class instance data member.

  3. Optional ‘?’ used as convention to indicate predicate variable or method of return type Boolean (true or false).

  4. A file name appended with ‘C’ indicates that the file describes class members rather than instance members.

  5. Optional class-desc is compiler hint for expected type of member variable. If class omitted, Object inferred or Boolean if data-name ends with ‘?’. If data-name ends with ‘?’ and class-desc is specified it must be Boolean.

  6. The context / file where an annotation is placed limits which values are valid.