Skip to content

A helper package for making object oriented definitions in Wolfram Language

Notifications You must be signed in to change notification settings

Anton-Sakovich/ObjectDefinitions

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Object Definitions

Object Definitions is a package intended to simplify making object oriented definitions in Wolfram Language.

Object oriented definition

An object from Object Definitions's point of view is an expression of the form:

head[data, type]

where head and type are both Symbols and data is any expression representing the object's per-instance data.

Both head and type have definitions of the form:

symbol[data_, type_][lhs_, caller_ : symbol] := rhs

which we call an object definition. It defines a rule between a pattern lhs_ (which can be any pattern, not just Blank) and an expression rhs in an object oriented way. The idea behind this definition is that type and head in

head[data, type]

stand for the object's type (class) and the interface through which we access the object (which can also be a class) respectively. caller_ pattern is used to match the interface through which an object was initially accessed in case head has changed since the first access because of inheritance.

How it works

Lets create an object definition for class person, whose objects are of the form person[<|"FirstName" -> "...", "LastName" -> "..."|>, person].

ClearAll[person];
person[data_, type_][introduce[], caller_: person] := TemplateApply[
  "Hello, my name is `FirstName` `LastName`!", data
]

Now we can create a person and check how she introduces herself:

max = person[<|"FirstName" -> "Max", "LastName" -> "Caulfield"|>, person];
max@introduce[]
(*"Hello, my name is Max Caulfield!"*)

So far so good. Lets now derive a student class from our person class, which boils down to redirecting unknown calls to person:

ClearAll[student];
student[data_, type_][expr_, caller_: student] := person[data, type][expr, caller];

Now we can create a student instance and she will also be able to introduce herself:

victoria = student[<|"FirstName" -> "Victoria", "LastName" -> "Chase", "Affiliation" -> "Blackwell Academy"|>, student];
victoria@introduce[]
(*"Hello, my name is Victoria Chase!"*)

She will do so even if casted back to person class:

(person @@ victoria)@introduce[]
(*"Hello, my name is Victoria Chase!"*)

At this point we might want to extend introduce[] method for student to include also affiliation. We can do so making another object definition:

student[data_, type_][introduce[], caller_: student] := StringJoin[
   person[data, type]@introduce[],
   TemplateApply[
     " I am studying at `Affiliation`.", data
   ]
];

Now student's introduction includes affiliation as well:

victoria@introduce[]
(*"Hello, my name is Victoria Chase! I am studying at Blackwell Academy."*)

But this extension is not polymorphic: when casted back to person, victoria uses person's implementation:

(person @@ victoria)@introduce[]
(*"Hello, my name is Victoria Chase!"*)

In OOP terms, student's definition hides that of person. We can make it polymorphic in the following way: we will make person redirect calls to introduce[] to the object's real type:

person[data_, type_][introduce[], caller_: person] := type[data, type]@override@introduce[];
person[data_, type_][override@introduce[], caller_: person] := TemplateApply[
   "Hello, my name is `FirstName` `LastName`!", data
];

And the same with student's introduce[]:

student[data_, type_][introduce[], caller_: student] := type[data, type]@override@introduce[];
student[data_, type_][override@introduce[], caller_: student] := StringJoin[
   person[data, type]@override@introduce[],
   TemplateApply[
    " I am studying at `Affiliation`.", data
   ]
];

Notice that this time we use person[data, type]@override@introduce[] rather than person[data, type]@introduce[] for calling base class' implementation to avoid recursion. Now max still introduces herself as a person:

max@introduce[]
(*"Hello, my name is Max Caulfield!"*)

and victoria introduces herself as a student even when casted back to person:

(person @@ victoria)@introduce[]
(*"Hello, my name is Victoria Chase! I am studying at Blackwell Academy."*)

About

A helper package for making object oriented definitions in Wolfram Language

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published