There are two main entities in the Box language: types and objects.Types have names starting with an uppercase letter.For example, Int, Real are two fundamental types in the Box language.Types can then be combined together to form new types. For example:
NewType = Int // NewType is just a new name for the type IntTuple = (Int, Real) // A tuple with anonymous membersPoint3D = (Real x, y, z) // A tuple formed by three members of type Real
The lines above show three ways of defining a new type in Box.There are many more ways of combining already existing types to create newones. Note also the way comments can be added to the sources: whateverfollows the comment mark // is treated as a comment and is ignored bythe compiler.
There are a number of intrinsic types the user can start from.Int is the type for integer numbers, Real for real numbers,Str is the type for strings, Char is the type for characters.Types can then be used to create new objects. For example, a new empty stringcan be created as follows:
s = Str
In general, one can create a new instance for a given type MyType usingthe syntax MyType. In the line above, we are also giving a name tothe new emtpy string created with Str.Names for instances, do start with a lowercase letter. For example,myvariable or myVariable.
The language also offers facilities to quickly create objects for mostof the intrinsic types. For example:
s = "my string" // Stringi = 123 // Integer numberr = 1.23 // Real numberc = 'a' // Character
Similarly to types, also objects can be combined together to create newobjects. For example:
Tuple = (Real, Real) // Creates a new structure type containing two Realstuple = (1.2, 3.4) // Creates a new instance of the type (Real, Real) // containing the numbers 1.2 and 3.4
Creating types is useful, as it simplifies creating instances. For example:
Triple = (Real x, y, z)triple1 = Tripletriple2 = Triple[.x = .y = .z = 1.0]
But, creating instances is not the only thing one may wants to do in aprogram. It is also important to combine objects together in order to dosomething useful with them.
And here is one of the main peculiarities of the Box language with respectto other popular programming languages (such as C, Python, etc.) wherefunctions (or object methods) are the means through which objects aremanipulated.The Box way of performing tasks is through what we call“type combinations”.
Boxes and type combinations¶
It may be worth at this point to enter a little bit more into the technicaldetails of the language.
We have seen that an instance for a type MyType can be created like this:
instance = MyType
This statement creates a new object of type MyType and assigns it to thevariable instance. The text fragment MyType is what we call a box.Boxes can be empty (as in the previous example) or can contain a group ofstatements. For example:
instance = MyType[statement1, statement2, statement3]
Notice that statements are separated by commas. An alternative way to separatestatements is using newlines. For example:
instance = MyType[statement1 statement2 statement3]
Notice that commas and newlines are just used to separate statements andare otherwise ignored. The following is then also valid:
instance = MyType[statement1 statement2,,, statement3]
Let’s now return back to the concept of box.A box is a group of statements which have the purpose of creating a newobject. For example, let’s imagine we are creating our own graphic libraryand we are trying to implement a way to define a circle shape.Then we may do it as follows:
circle = Circle[(0.0, 0.0), 10.0]
The box Circle[(0.0, 0.0), 10.0] has type Circle and contains twostatements. The first statement, (0.0, 0.0), provides the center of thecircle. The second statement, 10.0, provides the radius of the circle.
The examples we have seen so far tell us three things:
- numbers, strings, etc. are themselves statements,
- statements are grouped together inside boxes and serve to construct a newobject (whose type is specified just before the opening square bracket),
- a statement can have a type and a value. This value can be used by the boxthe statement belongs to (for example, a number 10.0 can be used by aCircle box to set the radius of a newly created circle).
Concerning the last point, we have to say that statemtents do always havetype and value. Indeed, this type is what determines how the statement isused in the parent box. For example, in the statement:
s = Str[3.14]
a new string object is created. The floating point number 3.14 is passed toStr, is converted to a string and used to create a new string in s.The result is that s is given the value "3.14".Another example is given below:
s = Str["My favourite number is ", 3.14]
Here Str receives two statements: one of type Str and one of typeReal. The effect is to create in s the string "My favourite number is3.14". This shows that different objects can have different effects insidethe same box. For example, a Real given to a Circle may set itsradius, while a Point may set its center. The particular action invokedwhen a statement of type Child is given inside a box of type Parent iscalled “combination” and is denoted with Child@Parent.Combinations can be defined using the following syntax:
Inside the square brackets, the symbol $ can be used to refer to theparticular child instance, while the symbol $$ can be used to refer to theparent.
Returning to the example of the Circle object, we may define:
Circle = (Real radius, Point center)
and define a combination as follows:
Real@Circle[$$.radius = $]
The line above defines a combination which is executed whenever a Real isgiven to a Circle. The line can be ideally split in two parts, one leftpart Real@Circle and one right part [$$.radius = $]. The left partindicates when the code should be executed. The right part provides the actualcode to execute (the implementation of the combination). The combination takes aReal (which is referred to by using the $ character) and assigns its valueto the radius member of the Circle object (represented by $$).Similarly, we may define:
Point@Circle[$$.center = $]
This way, the Box compiler knows what to do when Real and Point objectsare given inside a Circle box. In particular, the line below:
circle = Circle[(0, 0), 10.0]
has the same effect of the lines below:
circle = Circlecircle.center = (0, 0)circle.radius = 10.0
In our new graphic library, we may then specify how to draw a Circle insidea sheet of paper SheetOfPaper by defining another combination:
Circle@SheetOfPaper[ // Implementation of circle drawing... // Here we draw $ (the Circle instance) inside $$ (the particular // SheetOfPaper instance)]
Type combination is one of the fundamental ideas behind the Box language.As a Box programmer you are invited to identify which types of objects you needin order to implement your algorithm effectively.and to how these types can be combined together tomake something useful.
Why Boxes rather than functions?¶
Most programming languages put an extraordinary and often unjustified attentionto the order of things. For example, if you want to draw a circle on the screenin C, you may have to use a function like:
void draw_circle(screen *scr, double x, double y, double radius);
This order of arguments in this function prototype is largely arbitrary, butthe programmer is forced to remember it anyway. Indeed, draw_circle may bealternatively defined as:
void draw_circle(screen *scr, double radius, double x, double y);
Whenever the programmer will have to use the function draw_circle he willalso have to think to the arguments this function takes and their preciseorder. Some programming languages provide optional arguments, which may be seenas a possible way to address the flaw. In Python, for example, you may use thefollowing code to circumvent the order constraint:
def draw_circle(screen, point=None, radius=None): # check that point and radius are not None ...
You can then draw the circle in one of the following ways:
draw_circle(screen, point=p, radius=r)draw_circle(screen, radius=r, point=p)
It is clear than this is even worse than before. While we now do not need toremember the order of arguments, we have to remember their name. The resultingfunction call is also unnecessarily verbose.
So far we have seen two of the main very common flaws of modern programminglanguages:
- order of things is often arbitrary, but the user is forced to remember itanyway: a circle is defined just by its center and its radius; there is noreason why one should specify center and radius in this precise order and notthe opposite!
- the user is often forced to remember a number of names: type names, functionnames, optional argument names.
Box addresses these flaws by inviting the user to think about which objecttypes are necessary and how these objects should be combined together. Theconcept of function or class method is then replaced with the concept of typecombination. This way the number of names the user needs to remember isdrastically reduced.
For example, returning to our simple graphic library, we may define some shapesto draw Circle, Rectangle, Polygon. These entities have to bedrawn somewhere, right? Then we need another type, SheetOfPaper. We mayalso want to provide a fifth object, Area, to compute the area of theshapes. For example, if we have a Circle then the area is simplypi*radius*radius, where pi is the constant 3.141592...For a Rectangle it will be side_a*side_b.
What Box requires, is just to define these 5 types. It is then clear how to usethem. If we give a shape to a SheetOfPaper then the shape is drawn on thepaper. If we give it to Area then the area is computed. We do not needintroduce new class methods with arbitrary names that a user would need toremember. A fragment of Box source code using our library may then read:
sheet = SheetOfPaper[Circle[(0, 0), 10] Rectangle[(10, 10), (20, 20)]]area = Area[Circle[(0, 0), 15]]
In the code above, the user is free to forget the order of the arguments givento Circle or Rectangle. He is not forced to learn names of methodsto use in order to draw a shape or to calculate its area.Also, all this is achieved within a statically typed language, which, inprinciple, can be converted to efficient machine code.
Hello world in Box¶
We should now be ready to face the hello-world example: a program which justprints “Hello world!” out on the screen:
Here we use the Print box to show a string.Print is a type which descend from the type Void.Void and its derivatives are very special types: they are empty types whichare always ignored.
This example also shows how the semicolon, the third statement separator(together with commas and newlines) may be used in Box programs. While commasand newlines have a pure syntactical role (just as it happens for semicolons inC) and are ignored, semicolons have both a syntactical role as separators andan effect on execution. The Box programmer can decide which effect a semicolonshould have inside a box of a given type. For Print, the semicolon means “go tothe next line”.
The reader may have understood, at this point, that boxes are fundamentallydifferent from functions. A box is really a compound statement: it collectsthe statements required to create a certain object. You can put loops,conditionals and any other statement inside the square brackets. For example,the code:
Print["You can print from here!";]int = Int[1, Print["but also from here!";]]
is perfectly legitimate.
Statements inside a box are rarely ignored.One exception is made for the assignment operator.The code below:
Print[a = "Hello world!"; a;]
prints the string "Hello world!" only once, even if the statementa = "Hello world!" has itself a defined type (it is a Str object)and value. The reason for this behaviour is simple: one usually does not wantto pass the value of the assigned quantity to the underlying box.To really do that, one should put round bracketsaround the assignment expression:
Print[(a = "Hello world!"); a;]
This line will print twice the string "Hello world!".
There may be cases when one wants to explicitly ignore a value.The line above shows the syntax to use in such cases:
Print[\ 1, "nothing appears before the first occurrence 'nothing'";]
The \ character discards the valued expression on its right:the expression is not passed to the underlying box.
At this point it may be clear why boxes are so central:they do not simply group statements, but they providethe functionality of function calls.