The language is based on C++. Originally dubbed "c-squared," the language has been streamlined and cut down warranting a more appropriate name, "X," since the language hass been reduced to a system of expressions. X is a very simple and very scalable language; its
compiler is likewise to be extremely modular and scalable.
X is actually two languages: algorithmic X and directive X. The first produces executable code, i.e. algorithms, to solve problems. The second language directs the compiler on how to manipulate and process the algorithmic code, so as to create new levels of abstraction...such as templates.
For this discussion we are concerned with "algorithmic X," to which we refer simply as X. Under X, there are no statements. Every structure is an expression. Components are defined as "public classes," as opposed to private OOP classes which are internal to the components that use them.
As classes, components are similar to OOP classes. Both have
constructors and destructors. Both have functions to avail their features. Both provide for encapsulation, inheritance and overloading through their respective mechanisms. Yet the operation and terminology is a bit different. Publicly exposed component functions are called "interfaces"; whereas privately scoped funtions are called "methods." Further, though private classes can expose data directly to other classes, by declaring the data objects public "properties" of the class, components are not allowed to expose data directly. Instead, a component may only expose its data through interfaces (public functions).
An example of the X language component definition would appear as follows--
public class somecomponent;
Consitently, an internal class would appear as--
private class someOOPclass;
Both are complete declarations. somecomponent and someOOPclass are identifiers now known to the compiler as component and internal class, respectively. However both are unusable at this point, since they lack definition. We define the class using the link (<<) operator. This could occur during the declaration, as follows:
public class somecomponent
<< {...[code block]...};
to fully define somecomponent. Or, the programmer
could state a declaration first, as follows:
public class somecomponent;
then later specify its structure:
somecomponent << {...[code block]...};
Notice here that the link operator connects a code block and class identifier. Both means of doing this achieve the same end. Class and << are operators in these expressions. {...} is also an operator. All other identifiers in these expressions are considered to be operands (data manipulated by the operators).
One feature of X is its consistency. As everything is an expression we know that the compiler will find only two types of tokens: delimiters and identifiers. Anything that is not a delimiter is an identifier.
Delimiters are symbols which separate identifiers into discrete units. There are literal and contextual delimiters. Literal delimiters include line remarks ("//...[CRLF]"), block remarks ("/*...*/"), quotation
marks, semicolons (";") and whitespace. Contextual delimiters are less clear. These are the instances where grammar causes the separation of two character sequences into separate tokens. For example, if "+"
is an operator and the compiler sees "a+b", "a" and "b" are separated into separate tokens from "+" due to context.
Identifiers in X are either operators and operands. In the earlier example, "a+b" was delimited because "+" was defined as a known operator-identifier. Even if "a" and "b" are unknown, because "+" is known, the two unknowns can be parsed as the Left Hand and Right
Hand sides (LHS and RHS, respectively).
Operators are identifiers which manipulate values passed by operands. Operands are objects (public or private) which are acted upon by operators. Every operator then has two operands (explicit or implicit),
they are the LHS and RHS. The result of an operation is the return value and is passed to the left by default, but does not by default change the LHS operand value. Accordingly in X, the expression
x = a + b;
the addition of a and b does not alter a. Instead,
the sum is the RHS operand for the assignment operator
("="); whereas the assignment operator is coded to
first assign the RHS value to its LHS operand then
return the RHS value to the left (if possible).
[NOTE:
For the compiler design this means X source
code can be parsed into a binary tree structure!
An identifier is then represented by a node in
the tree, its LHS and RHS are the left and
right downward branches and the return value
is implied as being passed up the tree through
the PREV link.
]
There is another neat aspect of X: objects are
represented by identifiers, not bound by them. An
object identifier (whether operator or operand)
represents the object only so long as it is linked to
the object. An object identifier tracks the ADDRESS
in memory where the object is stored and the size of
the object's footprint in memory. X is strongly typed
but not strongly linked. Invoking an operator, then,
causes the operator to take as input the references to
its operands (LHS and RHS), NOT THE VALUES! The
operator can then directly affect or protect the
operands. The operator's return value is likewise a
reference to some temporary memory location allocated
for the purpose and later recovered through garbage
collection.
Since object identifiers represent the memory location
of their respective operators and operands, X permits
class and operator definitions a new level of freedom.
For instance, a class could be declared as follows:
public class foo;
Then it could be defined--
foo << {...[code block]...};
as we witnessed earlier. But X also allows the
programmer to later in code state
foo << {...[more code]...};
and assumming foo was not deleted (i.e. the original
definition was not erased), "more code" would add
features to that given by "code block." Moreover,
since {...} is a "group operator" (which we haven't
discussed) that returns the memory location for the
contained code block, we could also define another
class--
public class moo << {...[something else]...};
and link moo and foo together to like this--
moo << foo;
The result is a moo class which inherits foo class at
the point of its last definition before moo linked
into its identity.
This brings another interesting point about the X
language, class definitions contain expressions.
Therefore, they are algorithic descriptions about the
construction of a class instance. When a class is
instantiated its constructor is launched. Implicitly
the code produced by the class definition blocks are
the constructor's preamble. Its new and delete
operators are constructor and destructor,
respectively.
Class instances in X are created using the following
format--
instance new classname;
A class may also have a special array operator that is
invoked with new, as follows--
instance new classname array somenumber;
Example:
n new int array 5
creates a 5-element integer array whose memory
location is stored in some point represented by n. We
can retrieve that location by invoking the ampersand
("&") operator as follows:
p = &n;
where p represents some properly declared object.
[Note: p is declared as follows...
array p;
to be an unknown array object.
]
Inheritance of classes, demonstrated earlier, with the
link operator << also affects the definition of
operators in X. Remember, X has NO FUNCTIONS OR
PROCEDURES, only operators. An operator is defined
as--
[returntype]operator([LHStype][operatorid][RHStype]);
Example:
int operator (int + int);
where int (an integer data type) is the LHS and RHS of
a new operator (+) having an integer return type.
Here parenthesis is a special operator in the context
of the operator operator.
But the above example, like in the case of a class
declaration, fails to provide any real definition for
the new operation. This may be done concurrently, as
below:
int operator (int + int) << {...[code block]...};
or definition may occur separately--
int operator (int + int);
.
.
int operator (int + int) << {...[code block]...};
.
.
However, reference to the + operator must include its
type signature, since operators can be overloaded and
code must be linked only to specific instances of the
operator.
Linking code and class definitions in X also means
that code blocks can be defined separately and linked
later, during run-time. Thus, a programmer in X can
state--
a = &{...[Code A]...};
to store the address of code block A in the object a,
presumably a properly typed object. Later the
programmer could define--
b = &{...[Code B]...};
to the same end. Then the programmer could merge the
two into a single routine by stating--
c = &{{&a}<<{&b}};
where {...} accepts the references to the code and <<
links the two code structures together before storing
the address in c.
[Note: In this example a,b and c are first
declared as unknown operators.
operator a;
operator b;
operator c;
But none of the three can be used
as operators in this context, they
are only references to objects of
the type since they have no type
signature.
]
****************************************
Excellence Breeds! Go Hard or Go Home.
Let Penguins rule the earth.
Break some windows today.