# First and second class citizens in TTM

Quote from Dave Voorhis on November 8, 2018, 12:04 pmQuote from Hugh on November 8, 2018, 11:43 amRegarding operators, the idea certainly seems attractive but I wonder if any problems arise when nameless ones are allowed to persist. I also wonder how well they can coexist with named operators. How would I assign the system-defined operator named "+" to a variable of type OPERATOR? How would that value appear in a printout?

I touch on some of these issues in my overview of implementing anonymous operators in

Rel, at https://reldb.org/c/index.php/read/anonymous-and-first-class-operators/In particular, see page 5, section entitled

Anonymous Operators in Relations.

Reldoesn't yet permit assigning built-in operators to variables of typeOperator,only anonymous operators can be so assigned. However, if supported it might look like this:VAR plus OPERATOR(INT, INT) RETURNS INT; plus := +(INT, INT);Or, given that in

Relan operator like + is really an alias for OPERATOR OP_PLUS(INT, INT) RETURNS INT, it might be:plus := OP_PLUS(INT, INT);You can currently assign anonymous operators to variables of type Operator. The following works:

VAR plus OPERATOR(INT, INT) RETURNS INT; plus := OPERATOR(p1 INT, p2 INT) RETURNS INT; RETURN p1 + p2; END OPERATOR; WRITELN(plus);What it emits is a string containing the operator definition, so it prints out:

"OPERATOR ( p1 INT , p2 INT ) RETURNS INT ; RETURN p1 + p2 ; END OPERATOR"

To invoke the operator in the variable

plus, you do this:`WRITELN (plus)(2, 3);`

Of course, it emits 5.

Quote from Hugh on November 8, 2018, 11:43 amRegarding operators, the idea certainly seems attractive but I wonder if any problems arise when nameless ones are allowed to persist. I also wonder how well they can coexist with named operators. How would I assign the system-defined operator named "+" to a variable of type OPERATOR? How would that value appear in a printout?

I touch on some of these issues in my overview of implementing anonymous operators in *Rel*, at https://reldb.org/c/index.php/read/anonymous-and-first-class-operators/

In particular, see page 5, section entitled *Anonymous Operators in Relations.*

*Rel* doesn't yet permit assigning built-in operators to variables of type *Operator,* only anonymous operators can be so assigned. However, if supported it might look like this:

VAR plus OPERATOR(INT, INT) RETURNS INT; plus := +(INT, INT);

Or, given that in *Rel *an operator like + is really an alias for OPERATOR OP_PLUS(INT, INT) RETURNS INT, it might be:

plus := OP_PLUS(INT, INT);

You can currently assign anonymous operators to variables of type Operator. The following works:

VAR plus OPERATOR(INT, INT) RETURNS INT; plus := OPERATOR(p1 INT, p2 INT) RETURNS INT; RETURN p1 + p2; END OPERATOR; WRITELN(plus);

What it emits is a string containing the operator definition, so it prints out:

"OPERATOR ( p1 INT , p2 INT ) RETURNS INT ; RETURN p1 + p2 ; END OPERATOR"

To invoke the operator in the variable *plus*, you do this:

`WRITELN (plus)(2, 3);`

Of course, it emits 5.

*I'm the forum administrator and lead developer of Rel. Email me at dave@armchair.mb.ca with the Subject 'TTM Forum'. Download Rel from https://reldb.org*

Quote from Hugh on November 8, 2018, 12:59 pmQuote from Dave Voorhis on November 8, 2018, 12:04 pmQuote from Hugh on November 8, 2018, 11:43 amRegarding operators, the idea certainly seems attractive but I wonder if any problems arise when nameless ones are allowed to persist. I also wonder how well they can coexist with named operators. How would I assign the system-defined operator named "+" to a variable of type OPERATOR? How would that value appear in a printout?

I touch on some of these issues in my overview of implementing anonymous operators in

Rel, at https://reldb.org/c/index.php/read/anonymous-and-first-class-operators/In particular, see page 5, section entitled

Anonymous Operators in Relations.

Reldoesn't yet permit assigning built-in operators to variables of typeOperator,only anonymous operators can be so assigned. However, if supported it might look like this:VAR plus OPERATOR(INT, INT) RETURNS INT; plus := +(INT, INT);Or, given that in

Relan operator like + is really an alias for OPERATOR OP_PLUS(INT, INT) RETURNS INT, it might be:plus := OP_PLUS(INT, INT);You can currently assign anonymous operators to variables of type Operator. The following works:

VAR plus OPERATOR(INT, INT) RETURNS INT; plus := OPERATOR(p1 INT, p2 INT) RETURNS INT; RETURN p1 + p2; END OPERATOR; WRITELN(plus);What it emits is a string containing the operator definition, so it prints out:

"OPERATOR ( p1 INT , p2 INT ) RETURNS INT ; RETURN p1 + p2 ; END OPERATOR"

To invoke the operator in the variable

plus, you do this:`WRITELN (plus)(2, 3);`

Of course, it emits 5.

So is OPERATOR a type generator, rather than a specific type? I'm guessing that from your definition of VAR Plus, which I assume can be assigned any operator having that signature, (INT, INT), and type, INT.

As for the assignment to plus, I assume the semicolon following END OPERATOR is the one that normally terminates a command. I assume that because OPERATOR ( p1 INT , p2 INT ) RETURNS INT ; RETURN p1 + p2 ; END OPERATOR (without a terminating semicolon) appears to be a literal denoting a value of type OPERATOR(INT, INT) RETURNS INT. Right?

But do I really need that variable, plus? Could I instead write (OPERATOR ( p1 INT , p2 INT ) RETURNS INT ; RETURN p1 + p2 ; END OPERATOR)(2, 3);?

Hugh

Quote from Dave Voorhis on November 8, 2018, 12:04 pmQuote from Hugh on November 8, 2018, 11:43 amRel, at https://reldb.org/c/index.php/read/anonymous-and-first-class-operators/In particular, see page 5, section entitled

Anonymous Operators in Relations.

Reldoesn't yet permit assigning built-in operators to variables of typeOperator,only anonymous operators can be so assigned. However, if supported it might look like this:VAR plus OPERATOR(INT, INT) RETURNS INT; plus := +(INT, INT);Relan operator like + is really an alias for OPERATOR OP_PLUS(INT, INT) RETURNS INT, it might be:plus := OP_PLUS(INT, INT);You can currently assign anonymous operators to variables of type Operator. The following works:

What it emits is a string containing the operator definition, so it prints out:

"OPERATOR ( p1 INT , p2 INT ) RETURNS INT ; RETURN p1 + p2 ; END OPERATOR"

To invoke the operator in the variable

plus, you do this:`WRITELN (plus)(2, 3);`

Of course, it emits 5.

So is OPERATOR a type generator, rather than a specific type? I'm guessing that from your definition of VAR Plus, which I assume can be assigned any operator having that signature, (INT, INT), and type, INT.

As for the assignment to plus, I assume the semicolon following END OPERATOR is the one that normally terminates a command. I assume that because OPERATOR ( p1 INT , p2 INT ) RETURNS INT ; RETURN p1 + p2 ; END OPERATOR (without a terminating semicolon) appears to be a literal denoting a value of type OPERATOR(INT, INT) RETURNS INT. Right?

But do I really need that variable, plus? Could I instead write (OPERATOR ( p1 INT , p2 INT ) RETURNS INT ; RETURN p1 + p2 ; END OPERATOR)(2, 3);?

Hugh

*Coauthor of The Third Manifesto and related books.*

Quote from dandl on November 8, 2018, 1:11 pmA pointer is an address of a location in memory. There is nothing remotely like that going on here.

It might help to think of every relvar as actually a pseudo-variable. The real storage for it is persistent and lives in the database. When a compiled programs starts execution each declared relvar has to be bound to the correct storage entity in the database for the program to work. Program code that refers to a relvar has to be translated into calls into the database storage manager to do its thing, to retrieve a value or assign a new one. All I'm actually proposing is that the named relvar in the program can refer to different database storage entities at different times during execution. The syntax to do that is unimportant. V1, V2 and V3 are all objects of the same kind: relvar.

No, I don't propose nameless attributes. I merely propose a mechanism akin to a dynamic RENAME. As with the relvar example above, an attribute name used in a program can be made to refer to different attributes of the actual relvar (of the same type, of course). In each case the key is to separate the name used in the program from the identifier understood by the database manager, and allow the binding to be made dynamically.

The example in each case is the one I gave before: implementing data validations of type list and lookup similar to what can be done very easily in JavaScript.

A pointer is an address of a location in memory. There is nothing remotely like that going on here.

It might help to think of every relvar as actually a pseudo-variable. The real storage for it is persistent and lives in the database. When a compiled programs starts execution each declared relvar has to be bound to the correct storage entity in the database for the program to work. Program code that refers to a relvar has to be translated into calls into the database storage manager to do its thing, to retrieve a value or assign a new one. All I'm actually proposing is that the named relvar in the program can refer to different database storage entities at different times during execution. The syntax to do that is unimportant. V1, V2 and V3 are all objects of the same kind: relvar.

No, I don't propose nameless attributes. I merely propose a mechanism akin to a dynamic RENAME. As with the relvar example above, an attribute name used in a program can be made to refer to different attributes of the actual relvar (of the same type, of course). In each case the key is to separate the name used in the program from the identifier understood by the database manager, and allow the binding to be made dynamically.

The example in each case is the one I gave before: implementing data validations of type list and lookup similar to what can be done very easily in JavaScript.

Quote from Dave Voorhis on November 8, 2018, 1:42 pmQuote from Hugh on November 8, 2018, 12:59 pmQuote from Dave Voorhis on November 8, 2018, 12:04 pmQuote from Hugh on November 8, 2018, 11:43 amRel, at https://reldb.org/c/index.php/read/anonymous-and-first-class-operators/In particular, see page 5, section entitled

Anonymous Operators in Relations.

Reldoesn't yet permit assigning built-in operators to variables of typeOperator,only anonymous operators can be so assigned. However, if supported it might look like this:VAR plus OPERATOR(INT, INT) RETURNS INT; plus := +(INT, INT);Relan operator like + is really an alias for OPERATOR OP_PLUS(INT, INT) RETURNS INT, it might be:plus := OP_PLUS(INT, INT);You can currently assign anonymous operators to variables of type Operator. The following works:

What it emits is a string containing the operator definition, so it prints out:

"OPERATOR ( p1 INT , p2 INT ) RETURNS INT ; RETURN p1 + p2 ; END OPERATOR"

To invoke the operator in the variable

plus, you do this:`WRITELN (plus)(2, 3);`

Of course, it emits 5.

So is OPERATOR a type generator, rather than a specific type? I'm guessing that from your definition of VAR Plus, which I assume can be assigned any operator having that signature, (INT, INT), and type, INT.

As for the assignment to plus, I assume the semicolon following END OPERATOR is the one that normally terminates a command. I assume that because OPERATOR ( p1 INT , p2 INT ) RETURNS INT ; RETURN p1 + p2 ; END OPERATOR (without a terminating semicolon) appears to be a literal denoting a value of type OPERATOR(INT, INT) RETURNS INT. Right?

But do I really need that variable, plus? Could I instead write (OPERATOR ( p1 INT , p2 INT ) RETURNS INT ; RETURN p1 + p2 ; END OPERATOR)(2, 3);?

Hugh

Yes, I think "type generator" would be an appropriate description. The variable Plus can be assigned any operator having the signature (INT, INT) RETURNS INT, which could include an infinite number of operators that are not integer addition.

Yes,

OPERATOR(p1 INT, p2 INT) RETURNS INT; RETURN p1 + p2; END OPERATORis a literal denoting a value of type OPERATOR(INT, INT) RETURNS INT.In my example, you are correct -- you don't need the variable Plus. You could indeed write

(OPERATOR ( p1 INT , p2 INT ) RETURNS INT ; RETURN p1 + p2 ; END OPERATOR)(2, 3).However, the usual use case for anonymous operators involves assigning them to a variable or parameter. The latter is most common, where an anonymous operator is used to describe some context-specific bit of programmatic functionality that is then passed as an argument to some predefined operator

Opto customise thatOp's behaviour.

Quote from Hugh on November 8, 2018, 12:59 pmQuote from Dave Voorhis on November 8, 2018, 12:04 pmQuote from Hugh on November 8, 2018, 11:43 amRel, at https://reldb.org/c/index.php/read/anonymous-and-first-class-operators/In particular, see page 5, section entitled

Anonymous Operators in Relations.

Reldoesn't yet permit assigning built-in operators to variables of typeOperator,only anonymous operators can be so assigned. However, if supported it might look like this:VAR plus OPERATOR(INT, INT) RETURNS INT; plus := +(INT, INT);Relan operator like + is really an alias for OPERATOR OP_PLUS(INT, INT) RETURNS INT, it might be:plus := OP_PLUS(INT, INT);You can currently assign anonymous operators to variables of type Operator. The following works:

What it emits is a string containing the operator definition, so it prints out:

"OPERATOR ( p1 INT , p2 INT ) RETURNS INT ; RETURN p1 + p2 ; END OPERATOR"

To invoke the operator in the variable

plus, you do this:`WRITELN (plus)(2, 3);`

Of course, it emits 5.

Hugh

Yes, I think "type generator" would be an appropriate description. The variable Plus can be assigned any operator having the signature (INT, INT) RETURNS INT, which could include an infinite number of operators that are not integer addition.

Yes, *OPERATOR(p1 INT, p2 INT) RETURNS INT; RETURN p1 + p2; END OPERATOR* is a literal denoting a value of type OPERATOR(INT, INT) RETURNS INT.

In my example, you are correct -- you don't need the variable Plus. You could indeed write *(OPERATOR ( p1 INT , p2 INT ) RETURNS INT ; RETURN p1 + p2 ; END OPERATOR)(2, 3)*.

However, the usual use case for anonymous operators involves assigning them to a variable or parameter. The latter is most common, where an anonymous operator is used to describe some context-specific bit of programmatic functionality that is then passed as an argument to some predefined operator *Op* to customise that *Op*'s behaviour.

*I'm the forum administrator and lead developer of Rel. Email me at dave@armchair.mb.ca with the Subject 'TTM Forum'. Download Rel from https://reldb.org*

Quote from Hugh on November 8, 2018, 4:20 pmThanks for confirming my understanding of your examples. Yes, I realise that local variables would normally be used for the purpose at hand. Your proposed implementation looks interesting and I might even have an application for it, involving unnamed operators as attribute values.

I've mentioned before my database related to the "four fours" problem, where GJ and I are investigating solutions involving other combinations of four digits. For example, to express 25 using 1,2,3,4, we could write 4! + ((1+2)/3). The relevant operator value is OPERATOR (i INT, j INT, k INT, l INT) RETURNS INT; RETURN l! + ((i + j)/k); END OPERATOR and I could record that in the tuple for <1,2,3,4,25> as the chosen solution.

How could I then evaluate the solutions to check that they are all correct (i.e. n = soln(i,j,k,l))?

Hugh

Thanks for confirming my understanding of your examples. Yes, I realise that local variables would normally be used for the purpose at hand. Your proposed implementation looks interesting and I might even have an application for it, involving unnamed operators as attribute values.

I've mentioned before my database related to the "four fours" problem, where GJ and I are investigating solutions involving other combinations of four digits. For example, to express 25 using 1,2,3,4, we could write 4! + ((1+2)/3). The relevant operator value is OPERATOR (i INT, j INT, k INT, l INT) RETURNS INT; RETURN l! + ((i + j)/k); END OPERATOR and I could record that in the tuple for <1,2,3,4,25> as the chosen solution.

How could I then evaluate the solutions to check that they are all correct (i.e. n = soln(i,j,k,l))?

Hugh

*Coauthor of The Third Manifesto and related books.*

Quote from Hugh on November 8, 2018, 4:58 pmIf an attribute or variable is of type OPERATOR (i INT, j INT, k INT, l INT) RETURNS INT, it seems a shame to have to write out the signature again in every assignment to that attribute or variable. I realise of course that the signature is required in a literal denoting an operator but I just wondered if the burden could be alleviated in some way (without violating RM Pre 26).

Hugh

If an attribute or variable is of type OPERATOR (i INT, j INT, k INT, l INT) RETURNS INT, it seems a shame to have to write out the signature again in every assignment to that attribute or variable. I realise of course that the signature is required in a literal denoting an operator but I just wondered if the burden could be alleviated in some way (without violating RM Pre 26).

Hugh

*Coauthor of The Third Manifesto and related books.*

Quote from Dave Voorhis on November 8, 2018, 5:20 pmQuote from Hugh on November 8, 2018, 4:20 pmThanks for confirming my understanding of your examples. Yes, I realise that local variables would normally be used for the purpose at hand. Your proposed implementation looks interesting and I might even have an application for it, involving unnamed operators as attribute values.

I've mentioned before my database related to the "four fours" problem, where GJ and I are investigating solutions involving other combinations of four digits. For example, to express 25 using 1,2,3,4, we could write 4! + ((1+2)/3). The relevant operator value is OPERATOR (i INT, j INT, k INT, l INT) RETURNS INT; RETURN l! + ((i + j)/k); END OPERATOR and I could record that in the tuple for <1,2,3,4,25> as the chosen solution.

How could I then evaluate the solutions to check that they are all correct (i.e. n = soln(i,j,k,l))?

Hugh

Something like this?

VAR Solutions25 REAL RELATION { solutionNumber INT, solution OPERATOR(INT, INT, INT, INT) RETURNS INT } KEY {solutionNumber}; Solutions25 := RELATION { TUP {solutionNumber 1, solution OPERATOR(i INT, j INT, k INT, l INT) RETURNS INT; RETURN FACT(l) + ((i + j)/k); END OPERATOR}, TUP {solutionNumber 2, solution OPERATOR(i INT, j INT, k INT, l INT) RETURNS INT; RETURN FACT(SQRT(i) + SQRT(j)) + k/l; END OPERATOR}, // ...etc... }; // Find non-solutions with Solutions25 WHERE 25 ≠ ((solution)(4, 4, 4, 4))

Quote from Hugh on November 8, 2018, 4:20 pmHow could I then evaluate the solutions to check that they are all correct (i.e. n = soln(i,j,k,l))?

Hugh

Something like this?

VAR Solutions25 REAL RELATION { solutionNumber INT, solution OPERATOR(INT, INT, INT, INT) RETURNS INT } KEY {solutionNumber}; Solutions25 := RELATION { TUP {solutionNumber 1, solution OPERATOR(i INT, j INT, k INT, l INT) RETURNS INT; RETURN FACT(l) + ((i + j)/k); END OPERATOR}, TUP {solutionNumber 2, solution OPERATOR(i INT, j INT, k INT, l INT) RETURNS INT; RETURN FACT(SQRT(i) + SQRT(j)) + k/l; END OPERATOR}, // ...etc... }; // Find non-solutions with Solutions25 WHERE 25 ≠ ((solution)(4, 4, 4, 4))

*I'm the forum administrator and lead developer of Rel. Email me at dave@armchair.mb.ca with the Subject 'TTM Forum'. Download Rel from https://reldb.org*

Quote from Dave Voorhis on November 8, 2018, 5:23 pmQuote from Hugh on November 8, 2018, 4:58 pmIf an attribute or variable is of type OPERATOR (i INT, j INT, k INT, l INT) RETURNS INT, it seems a shame to have to write out the signature again in every assignment to that attribute or variable. I realise of course that the signature is required in a literal denoting an operator but I just wondered if the burden could be alleviated in some way (without violating RM Pre 26).

Hugh

I appreciate the desire for brevity, but that would imply a coercion notionally equivalent to being able to perform an assignment like:

VAR x RATIONAL; x := 2;

Reldoesn't allow that, either. The literal 2 must be 2.0. All literals must be fully specified and their types unambiguously recognisable on sight, so to speak.

Quote from Hugh on November 8, 2018, 4:58 pmHugh

I appreciate the desire for brevity, but that would imply a coercion notionally equivalent to being able to perform an assignment like:

VAR x RATIONAL; x := 2;

*Rel* doesn't allow that, either. The literal 2 must be 2.0. All literals must be fully specified and their types unambiguously recognisable on sight, so to speak.

Quote from Hugh on November 9, 2018, 12:41 pmQuote from Dave Voorhis on November 8, 2018, 5:20 pmQuote from Hugh on November 8, 2018, 4:20 pmHow could I then evaluate the solutions to check that they are all correct (i.e. n = soln(i,j,k,l))?

Hugh

Something like this?

VAR Solutions25 REAL RELATION { solutionNumber INT, solution OPERATOR(INT, INT, INT, INT) RETURNS INT } KEY {solutionNumber}; Solutions25 := RELATION { TUP {solutionNumber 1, solution OPERATOR(i INT, j INT, k INT, l INT) RETURNS INT; RETURN FACT(l) + ((i + j)/k); END OPERATOR}, TUP {solutionNumber 2, solution OPERATOR(i INT, j INT, k INT, l INT) RETURNS INT; RETURN FACT(SQRT(i) + SQRT(j)) + k/l; END OPERATOR}, // ...etc... }; // Find non-solutions with Solutions25 WHERE 25 ≠ ((solution)(4, 4, 4, 4))

Actually it would be like this:

VAR Solutions REAL RELATION { i INT, j INT, k INT, l INT, n INT,

solution OPERATOR(INT, INT, INT, INT) RETURNS INT }

KEY {ALL BUT solution}; /* Predicate:n= solution(i,j,k,l) */CONSTRAINT SolutionsCorrect IS_EMPTY(Solutions WHERE n <> solution(i,j,k,l);

CONSTRAINT OneToHundred IS_EMPTY (Solutions where n < 1 OR n > 100);

CONSTRAINT CaseToBeSudied IS_EMPTY(Solutions NOT MATCHING Cases);/* insert a couple of randomly chosen tuples */

INSERT solutions rel{

tup{i 1, j 2, k 3, l 4, n 25, solution OPERATOR(i INT, j INT, k INT, l INT) RETURNS INT; RETURN FACT(l) + ((i + j)/k); END OPERATOR},

tup{i 1, j 1, k 1, l 1, n 100, solution OPERATOR(i INT, j INT, k INT, l INT) RETURNS INT; RETURN (i/(j/10))*(k/(l/10))}; END OPERATOR}}/*

Note:j/10 = .1, use if decimal points being considered. Similarly, j/9 would be used for "point j recurring" */But the relation would be of cardinality approaching 49,500 (the number of cases GJ and I had to study to complete the survey) so I'm not sure I'm actually up to doing this!

Hugh

Quote from Dave Voorhis on November 8, 2018, 5:20 pmQuote from Hugh on November 8, 2018, 4:20 pmHow could I then evaluate the solutions to check that they are all correct (i.e. n = soln(i,j,k,l))?

Hugh

Something like this?

Actually it would be like this:

VAR Solutions REAL RELATION { i INT, j INT, k INT, l INT, n INT,

solution OPERATOR(INT, INT, INT, INT) RETURNS INT }

KEY {ALL BUT solution}; /* Predicate: *n* = solution(*i,j,k,l*) */

CONSTRAINT SolutionsCorrect IS_EMPTY(Solutions WHERE n <> solution(i,j,k,l);

CONSTRAINT OneToHundred IS_EMPTY (Solutions where n < 1 OR n > 100);

CONSTRAINT CaseToBeSudied IS_EMPTY(Solutions NOT MATCHING Cases);

/* insert a couple of randomly chosen tuples */

INSERT solutions rel{

tup{i 1, j 2, k 3, l 4, n 25, solution OPERATOR(i INT, j INT, k INT, l INT) RETURNS INT; RETURN FACT(l) + ((i + j)/k); END OPERATOR},

tup{i 1, j 1, k 1, l 1, n 100, solution OPERATOR(i INT, j INT, k INT, l INT) RETURNS INT; RETURN (i/(j/10))*(k/(l/10))}; END OPERATOR}}

/* *Note:* j/10 = .1, use if decimal points being considered. Similarly, j/9 would be used for "point j recurring" */

But the relation would be of cardinality approaching 49,500 (the number of cases GJ and I had to study to complete the survey) so I'm not sure I'm actually up to doing this!

Hugh

*Coauthor of The Third Manifesto and related books.*

Quote from Hugh on November 9, 2018, 12:43 pmQuote from Dave Voorhis on November 8, 2018, 5:23 pmQuote from Hugh on November 8, 2018, 4:58 pmHugh

I appreciate the desire for brevity, but that would imply a coercion notionally equivalent to being able to perform an assignment like:

VAR x RATIONAL; x := 2;

Reldoesn't allow that, either. The literal 2 must be 2.0. All literals must be fully specified and their types unambiguously recognisable on sight, so to speak.As I expected. And even if coercion were supported (which I would definitely oppose) we would need another type for operator body.

Hugh

Quote from Dave Voorhis on November 8, 2018, 5:23 pmQuote from Hugh on November 8, 2018, 4:58 pmHugh

VAR x RATIONAL; x := 2;

Reldoesn't allow that, either. The literal 2 must be 2.0. All literals must be fully specified and their types unambiguously recognisable on sight, so to speak.

As I expected. And even if coercion were supported (which I would definitely oppose) we would need another type for operator body.

Hugh

*Coauthor of The Third Manifesto and related books.*