Further Examples

Comments

According to MOSTflexiPL's basic philosophy, the language does not provide any predefined syntax for comments, but rather allows the user to individually define his own preferred syntax(es), e. g.:

    "/*" ... "*/";  /* Define C style block comments. */
    "//" ...;       // Define C++ and Java style line comments.
    print /* /* // comment */ 10 // comment // /*
Generally speaking, the predefined infix operator •...• (the three dots have to be written literally) defines comments surrounded by the begin and end strings denoted by its operands. In contrast, the predefined postfix operator •... defines comments starting with the begin string denoted by its operand and ending before the next line break.

As the example illustrates, a comment started by a specific begin string ends at the first occurence of the corresponding end string or the next line break, respectively, which implies that comments of the same kind cannot be nested. However, by defining different kinds of comments, arbitrary nesting is basically possible, as the example also demonstrates. Therefore, the last line of the example without any comments simply contains print 10.

Reading from Standard Input

The predefined nullary operator read reads a line from the standard input stream and returns it (without the final line terminator) as a string, e. g.:

    print "Please enter your name:";
    "name" := read;
    print "Hello, " ++ name ++ "!"
If EOF is reached before any character has been read, read returns nil.

Type Conversions

To convert a string read that way to an int or float value, one of the predefined conversion operators can be applied, e. g.:

    print "Please enter an integer:";
    "s" := read;
    "n" := int s;
    print "The number is " ++ n
Generally speaking, an expression T x consisting of some type T and some value x of some other type S yields x converted to T, if a suitable conversion operator conv• is available. More specifically, T x is an application of the following predefined generic “cast” operator:
    [
        "T" : type; "S" : type; "x" : S;
        ["x" : S] "conv" x : T {}
    ]
    T x : T
    { conv x }
This operator is a bit unusual, because its signature does not contain any names, but only operands. (Therefore, the operator is called “anonymous.”) Furthermore, the operator has an implicit parameter conv• with a parameter of type S and result type T, which is used to actually perform the type conversion from S to T.

According to the general rules for implicit parameters, an application T x of the cast operator is correct, if and only if a matching conv• operator is visible at the point of application. To support standard type conversions, the following conv• operators are predefined with rather obvious meanings:

    ["x" : string] "conv" x : int { ...... };
    ["x" : int] "conv" x : string { ...... };
 
    ["x" : string] "conv" x : float { ...... };
    ["x" : float] "conv" x : string { ...... };
 
    ["x" : int] "conv" x : float { ...... };
    ["x" : float] "conv" x : int { ...... };
 
    ["x" : char] "conv" x : int { ...... };
    ["x" : int] "conv" x : char { ...... };
 
    ["T" : type; "x" : T] "conv" x : T { x }
The conversion from char to int and vice versa allows to obtain a character's position in the Unicode character set and vice versa. The conversion in the last line supports trivial conversions from any type T to itself.

Because these operators conv• are heavily overloaded, with some variants differing only in their result types, direct applications such as conv 10 would be ambiguous. Applications of the cast operator, however, automatically select the appropriate variant according to the source and target type of the cast.

Of course, a user is free to define additional conv• operators, e. g., to convert persons to strings:

    ["p" : Person]
    "conv" p : string
    { p.name }
 
Afterwards, the expression string p would be correct for every subexpression p having type Person.

These conversion operators are used in two different places as well, quite similar to Java's toString method: First, the predefined operator print• accepts operands x of any type T, if a conv• operator with parameter type T and result type string is available, and in fact prints x converted to string, followed by a line terminator. Thus, print p would also be correct for any person p, if the above conv• operator is visible, and would actually print the person's name.

Similarly, the concatenation operator •++• already mentioned in “Sequences” also accepts operands of arbitray types S and T, if conv• operators with parameter types S resp. T and result type string are available, and in fact converts its operands to strings before actually concatenating them.


Christian Heinlein, 2016-10-15