1 ? -1 ? 1.2 ? 1.66e10 ? -1.66E-10 ? 1E-9999 ? ;; underflow 1E9999 ? ;; infinity
'A' ? 'A'.clazz ? '\r' ? ;; line feed '\n' ? ;; newline '\010' ? ;; newline
"A" ? "A".clazz ? "Otto" ?
false ? false.clazz ? true.clazz ?
nil ?
Infix operators are transformed into "normal" method calls by the system. The following two expressions show this transformation:
3 + 4 * 5 ? 3."+"(4."*"(5)) ?
The set of prefix operators is fix but it may used in every class to define infix operator for the objects of the specific class (e.g. + is used for integer addition and for string concatenation.
The commonnumeric operators are defined in class Number.The defined operators and their signatures may be inspected by "pretty printing" the class Number.
Number.prettyPrint ?
Here are some examples of numeric infix operators:
(3 + 4) * 5 ? 12 / 3 ? 12 % 3 ? 3 > 4 ? 3 > 4 - 3 ?
Note: Tycooon does not suport coercion (i.e. implicite mapping of values of one type to values of another type).
1 + 1.0 ? 1.asReal + 1.0 ? 1 + 1.0.asInt ?
The following operations result in arithmetic errors or overflows.
;; -- Arithmetic overflow and errors: 2.intPower(3) ? 2.intPower(99) ? ;; integer overflow ignored 2.0.intPower(9999) ? ;; real overflow = Inf 1 / 0 ? ;; Division by zero exception 1.0 / 0.0 ? ;; an ArithmeticError
The standard boolean infix operators in Tycoon-2:
true & false ? ;; and true | false ? ;; or true ^ false ? ;; xor
The prefix operator not (negation):
!true ? !(3 > 4) ? Bool.prettyPrint ?
Furthermore Tycoon-2 supports lazy boolean infix operators for partial evaluation:
;; -- Short circuit evaluation: x :Int := nil x.isNotNil && x > 3 x := 0 x=0 || 1/x > 3 ?
The lazy binary operators && and || are internally rewritten by the parser to enclose their second argument in a lazy block.
;; -- Short circuit evaluation:
x :Int := nil
x.isNotNil."&&"({ x > 3 })
x := 0
x=0."||"({ 1/x > 3 })
?
These blocks are only evaluated if necessary. In the case of && for example the block is only evaluated if the first expression evaluates to true. In case it evaluates to false the result of the entire expression is false independent of the content of the block. In this case the block is not evaluated. The signatures of the boolean operators may be inspected by "pretty printing" the class Bool.
The infix operator + is used for string concatenation:
"Kon" + "katenation" ?
Further useful operations on strings are defined in the class String.
" test ".trim ?
"test".locateChar('e') ?
"test".locateChar('3') ?
Function definition (no parameters):
fun() {"hello"} ?
The function body is a block.
Function application:
fun() {"hello"}[] ?
Shorthand for the definition of a function without parameters (lazy block):
{"hello"} ?
{"hello"}[] ?
{"hello"}.clazz.prettyPrint ?
Function with one parameter:
fun(x:Int) {x + x} ?
fun(x:Int) {x + x} [7] ?
fun(x:Int) {x + x}.clazz.prettyPrint ?
Further examples
fun(x:Int,y:Int):Int { x + y } ?
fun(x:Int,y:Int):Int { x + y }[10,7] ?
{1 2 3}[] ?
{}[] ? ;; nil
A block is a sequence of expressions and bindings of local variables. Blocks appear enclosed in round or curly parantheses.
a ::= 3 b ::= 4 a + b
An eager block enclosed in round parantheses is evaluated immediately, while a lazy block in curly parentheses denotes a function or method body, which is only evaluated when it is invoked.
Blocks limit the scope of the local variables defined inside the block:
(a ::= 3 (a ::= "A" a ) ) ? (a ::= 3 a ::= "A" a ) ?
Blocks may be nested.
The conditional (if-then-else) is defined as a method accepting the value of the condition and two parameterless functions. If the condition is true, the function passed using the "then:" keyword is evaluated. Otherwise, the function passed using the "else:" keyword is evaluated. Either branch defaults to the empty function.
A conditional without else branch looks as follows:
if( true then:{
tycoon.stdout << "true"
}) ?
The conditional with else branch (if-then-else) looks as follows:
if( false then:{
tycoon.stdout << "true"
} else: {
tycoon.stdout << "false"
}) ?
Note that "if" is a regular method, and can be explained completely by looking at its implementation: A "case" message is sent to the condition value. The condition value will either be an instance of class True, or an instance of class False. The implementation of "case" in class True evaluates the first block; in class False, the second block is evaluated. Inspect the implementation of "if" in class Object and the implementation of "case" in the classes True and False for further detail.
Loops are methods implemented in the class Object. Their signatures may be inspected by "pretty printing" the class Object.
Object.prettyPrint ?
Tycoon supports two different kinds of for-loops: One counting up and one counting down.
for(1 to: 10 do: fun(i :Int) {
tycoon.stdout << i << "-"
}) ?
forDown(10 to: 1 do: fun(i :Int) {
tycoon.stdout << i << "-"
}) ?
Both methods support an optional "step:" keyword.
for(1 to: 100 step: 10 do: fun(i :Int) {
tycoon.stdout << i << "-"
}) ?
forDown(100 to: 1 step: 10 do: fun(i :Int) {
tycoon.stdout << i << "-"
}) ?
Object.prettyPrint ?
x ::= 1234
repeat({
tycoon.stdout << x % 10 << "-"
x:= x / 10
} until:{ x = 0 })
?
x ::= 2
exp ::= 3
result ::= 1
while({ exp!=0 } do:{
result:= result * x
exp:= exp - 1
})
result
?
try({
tycoon.stdout << "before "
5 / 0
tycoon.stdout << "after "
} else: fun(e :Exception) {
tycoon.stdout << e
}) ?
|
|
16-feb-1999 holm wegner |