Reserved words¶
Unicon reserved words¶
Unicon uses a fair number of reserved words. There are 38 reserved words in Unicon version 13. That might seem like a lot, and it is, until you compare Unicon with the likes of COBOL[1].
Emphatics[2] is used here to denote action causing reserved words. In many other languages, they would be called statements, but Unicon has no statements. These reserved words all count as expressions and return results along with triggering control flow actions to occur. Almost everything[3] in Unicon is an expression. Listed here as emphatic, these action causing reserved words act, and react, as expressions.
While most Unicon reserved words are actionable, flow control expressions, some others take a supporting role, as either declarative expressions, or as syntax markers for optional phrasing. For example, the by reserved word is only usable when paired with to, and will not work alone as a valid expression. else is only applicable within an if expression. then is a marker word that separates expr1 from expr2 in an if expression. Other words inform the compiler about data management, with variables being declared global, local or static.
Reserved words cannot be used as identifier names. [4]
All reserved words count as expressions (or assist in defining an overall expression).
[1] | COBOL has over 500 reserved words, some implementations listing over 1,000. |
[2] | This chapter was originally called “Statements”, but that is a technically incorrect and harmfully misleading naming convention. Unicon has no statements. All expressions return results, emphatic reserved words lead flow control and count as expressions. |
[3] | If you try hard, you may find a Unicon syntax element that does not
count as an expression; Unicon preprocessor directives come to mind, as
would the all reserved word that is part of invocable in
invocable all . |
[4] | Unicon can be tricky sometimes. Everything is an expression, and variables do not need to be declared before use. From the Programming Corner, Icon Newsletter 35, March 1st, 1991: while next := read() do write(next) That code fragment causes an endless loop. The |
Unicon action words¶
Once again, all these reserved words are expressions and need to be thought of that way for effective Unicon programming. Verb might be an appropriate name for these action words, but the term used in this document is emphatic.
break¶
Exit the nearest enclosing loop and evaluate optional expression.
break [expr]
If the expr includes break
, multiple levels of nesting can be exited.
For instance; break break next
will exit two inner loop levels and restart
at the top of an outer loop. The example below breaks out of one level,
jumping to the top of the outer.
#
# break.icn, loop exit sample
#
# this sample is utterly contrived
#
procedure main()
every i := 1 to 3 do {
every j := 1 to 4 do {
write("i is ", i, ", j is ", j)
# when i is 2, restart the outer loop
if i == 2 then break next
# when j is 2, just break out of the inner loop
if j == 2 then break write("poor j, never gets to 3")
}
write("after the inner loop, i is ", i)
}
end
Sample run:
prompt$ unicon -s break.icn -x
i is 1, j is 1
i is 1, j is 2
poor j, never gets to 3
after the inner loop, i is 1
i is 2, j is 1
i is 3, j is 1
i is 3, j is 2
poor j, never gets to 3
after the inner loop, i is 3
case¶
A selection expression where expr is compared to the compound expressions
that follow. First matching expr1 (or expr3, etc) will evaluate and
produce the resulting value of the paired expr2. If no matches are found,
the optional default
exprn case is evaluated. With no default
and
no comparison matches, the case
expression will fail.
#
# case.icn, demonstrate case selection
#
procedure main()
c := "initial value"
t := "e"
# no match, no default, case will fail, c not re-assigned
c := case t of {
"a": "b"
"c": "d"
}
write(image(c))
# no match, with default, c will be assigned to "f"
c := case t of {
"a": "b"
"c": "d"
default: "f"
}
write(image(c))
# first match satisfies case, c is assigned to "b"
c := case t of {
map("E"): "b"
"e" : "d"
default : "f"
}
write(image(c))
end
Sample run:
prompt$ unicon -s case.icn -x
"initial value"
"f"
"b"
create¶
create expr : co-expression
Create a co-expression for expr. Not evaluated until explicitly requested by the invocation operation or spawn function.
Co-expressions are a very powerful feature of Unicon. A feature that is still missing from many other programming languages.
See @ for information on co-expression activation.
#
# create.icn, Demonstrate co-expression create
#
procedure main()
coex := create(1 to 3)
write("co-expression now ready to be invoked, at will")
write(@coex)
write("Do some other computing")
write(@coex)
write("get last expected result")
write(@coex)
if v := @coex then
write("co-expression has delivered more results than expected")
end
Giving:
co-expression now ready to be invoked, at will
1
Do some other computing
2
get last expected result
3
critical¶
critical mtx : expr
is the equivalent of lock(mtx); expr ;
unlock(mtx), where mtx
is a mutual exclusion facility control for
structure x
defined with mtx :=
mutex(x)
.
This allows for more concise control of critical memory sections when multi-threading.
For instance:
x := x + 1
That code is actually at risk in threaded applications. It is a three step process. Fetch x, increment x, assign to x. Multiple threads, without synchronization might all evaluate the fetch x part of those steps at the same time. The final result would be incorrect.
critical mtx : x := x + 1
That code will ensure that each thread is allowed to complete all steps of the expression before allowing another thread access to the critical section.
#
# critical.icn, Demonstrate mutually exclusive expression control
#
global x
procedure main()
x := 0
mtx := mutex()
T1 := thread report(mtx)
T2 := thread other(mtx)
# due to the nature of threading
# the values displayed in report
# might be 1,2,3,4 or 1,10,11,12 or 1,2,11,12 etc
wait(T1 | T2)
# final result will always be 12
write("x is ", x)
end
# increment and report
procedure report(mtx)
every 1 to 4 do {
critical mtx : x := x + 1
write(x)
}
end
# just increment
procedure other(mtx)
every 1 to 8 do
critical mtx : x := x + 1
end
Giving:
1
2
3
4
x is 12
every¶
every expr1 [do expr2]
every
will produce all values from a generator. Internally, the every
statement always fails, causing expr1 to be resumed for more results. An
optional do expr2 will be evaluated before each resumption of expr1.
every
is a one of the work horse words in Unicon.
Of note: while and every play different roles in Unicon, and the distinction can be confusing at first, especially when dealing with read.
every read() do stuff()
while read() do stuff()
That first expression is wrong, or at least it may not do what a new Unicon programmer expects. No Unicon expression that compiles is ever wrong, it just does what it is told. The example below reads its own source, to highlight the effect:
# ## top-line read by every ##
##-
# Author: Brian Tiffin
# Dedicated to the public domain
#
# Date: September, 2016
# Modified: 2016-10-03/22:51-0400
##+
#
# every.icn, Demonstrate the every emphatic
#
procedure main()
# so many things to show for every
# semantics wise, every continuously fails, causing the Unicon goal
# directed evaluation engine to seek alternatives for a successful
# expression outcome
# write some to-by numbers
every writes(0 to 8 by 2) do writes(" ")
# write some alternatives
write()
every write(1 | 2 | "abc")
# every out a string, one character at a time
every write(!"xyzzy")
# write out this file; not always a job for every
write()
f := open(&file, "r") | stop("Cannot open ", &file, " for read")
write("read in an every loop may not do what you expect")
# don't do this
every now := read(f) do stuff(now)
# read returns a result, not suspend
# every succeeds, job complete, after the first record
# do this, with while
write()
write("### read (the rest) in a while loop ###")
write()
while now := read(f) do stuff(now)
close(f)
end
procedure stuff(now)
write(now)
end
Sample run:
prompt$ unicon -s every.icn -x
0 2 4 6 8
1
2
abc
x
y
z
z
y
read in an every loop may not do what you expect
# ## top-line read by every ##
### read (the rest) in a while loop ###
##-
# Author: Brian Tiffin
# Dedicated to the public domain
#
# Date: September, 2016
# Modified: 2016-10-03/22:51-0400
##+
#
# every.icn, Demonstrate the every emphatic
#
procedure main()
# so many things to show for every
# semantics wise, every continuously fails, causing the Unicon goal
# directed evaluation engine to seek alternatives for a successful
# expression outcome
# write some to-by numbers
every writes(0 to 8 by 2) do writes(" ")
# write some alternatives
write()
every write(1 | 2 | "abc")
# every out a string, one character at a time
every write(!"xyzzy")
# write out this file; not always a job for every
write()
f := open(&file, "r") | stop("Cannot open ", &file, " for read")
write("read in an every loop may not do what you expect")
# don't do this
every now := read(f) do stuff(now)
# read returns a result, not suspend
# every succeeds, job complete, after the first record
# do this, with while
write()
write("### read (the rest) in a while loop ###")
write()
while now := read(f) do stuff(now)
close(f)
end
procedure stuff(now)
write(now)
end
There is an alternative to while
and read
. The generate elements
operator !, can be used with the file type, so it becomes
every
friendly. No read
is called (which returns a result, that
return satisfies the every). With the ! operators, Unicon files
generate the elements within the resource.
# ## top-line read by every ##
##-
# Author: Brian Tiffin
# Dedicated to the public domain
#
# Date: September, 2016
# Modified: 2016-10-03/22:51-0400
##+
#
# every-gen.icn, Demonstrate the every emphatic with generate elements
#
procedure main()
# write out this file; not always a job for every
write()
f := open(&file, "r") | stop("Cannot open ", &file, " for read")
write("read in an every loop does not do what you may expect")
# don't do this
every now := read(f) do stuff(now)
# read returns a result, not suspend
# every succeeds, job complete, after the first record
# now using the file itself with the ! operator
write()
write("### generate (the rest) ###")
write()
every now := !f do stuff(now)
close(f)
end
procedure stuff(now)
write(now)
end
Every with a file content generator:
prompt$ unicon -s every-filegen.icn -x
read in an every loop does not do what you may expect
# ## top-line read by every ##
### generate (the rest) ###
##-
# Author: Brian Tiffin
# Dedicated to the public domain
#
# Date: September, 2016
# Modified: 2016-10-03/22:51-0400
##+
#
# every-gen.icn, Demonstrate the every emphatic with generate elements
#
procedure main()
# write out this file; not always a job for every
write()
f := open(&file, "r") | stop("Cannot open ", &file, " for read")
write("read in an every loop does not do what you may expect")
# don't do this
every now := read(f) do stuff(now)
# read returns a result, not suspend
# every succeeds, job complete, after the first record
# now using the file itself with the ! operator
write()
write("### generate (the rest) ###")
write()
every now := !f do stuff(now)
close(f)
end
procedure stuff(now)
write(now)
end
The conceptual difference between return and suspend is an important one for all Unicon programmers to understand. It can take a few practice runs before it sinks in. Traditional programming experiences can make this even harder, and you may find yourself slipping back without realizing it from time to time; before an initial program run reminds you of the difference. No harm done, as long as alpha testing is always part and parcel of your Unicon development cycle. Unicon has features that set it apart from most other programming languages. It is important to think Unicon to take maximum advantage of these features.
every
feeds on generators by forcing the goal-directed evaluation engine
to keep trying alternatives. If the expression completes (either by returning
a result (with return) or failing, every
terminates. while
on
the other hand, is a procedural expression with a more traditional flow
control paradigm. Unicon allows for both methods of loop management.
fail¶
fail causes the enclosing procedure or method to terminate immediately and
produce no result, signalling failure. The invocation may not be resumed.
fail
is equivalent to return &fail
.
#
# fail.icn, demonstrate the fail emphatic expression
#
procedure main()
# resumption will terminate after the hard fail expression
every i := subproc() do write(i)
end
procedure subproc()
# will only deliver 1 and 2
suspend j := 1 to 4 do if j = 2 then fail
end
Sample run:
1
2
if¶
if expr1 then expr2 [else expr3]
The Unicon if
emphatic expression evaluates expr1 and if it succeeds,
proceeds to evaluate expr2, given after the then
reserved word. If the
optional else
clause is present, then a failed expr1 will proceed to
evaluate expr3 instead. The overall result is either failure, or the result
of expr2 (or expr3) depending on the outcome of expr1.
#
# if.icn, Demonstrate the if emphatic reserved word expression
#
procedure main()
if 1 = 1 then write("yes, one equals one")
if 1 = 2 then write("not displayed")
else write("one is not equal to two")
a := 1
a := if 1 = 2 then write("if fails, a not set, remains 1")
write(a)
# a will get the then expression result
a := if 1 = 1 then 2
write(a)
# a will get the else expression result
a := if 1 = 2 then 2 else 3
write(a)
end
Giving:
prompt$ unicon -s if.icn -x
yes, one equals one
one is not equal to two
1
2
3
initial¶
An initial expr is only evaluated the first time a procedure is entered.
Mainly used for initializing static variables, when an initializing
expression is not sufficient. Initializing a local variable in an
initial expression is usually not desirable, local
variables will lose the
value before second entry.
#
# initial.icn, demonstrate an initial expression
#
procedure main()
c := subproc()
write(image(c))
c := subproc()
write(image(c))
end
procedure subproc()
local a
static b
# a will only be set on the first call
initial {
a := "abc"
b := "bcd"
}
write(b)
return a
end
Giving:
bcd
"abc"
bcd
&null
initially¶
initially [(parameters)]
creates a special method that is invoked when
an object is instantiated. If the initially
section has declared
parameters, they are used as the parameters of the constructor for the objects
of that class.
#
# initially.icn, demonstrate class initialization control
#
$define space ' '
class person(first, last, middle)
method show()
writes(first)
if \middle then writes(space, middle)
write(space, last)
end
initially
/first := "Jane"
/last := "Doe"
end
procedure main()
c := person("Clinton", "Jeffery", "L.")
c.show()
c := person()
c.show()
c := person("John")
c.show()
end
Giving:
Clinton L. Jeffery
Jane Doe
John Doe
next¶
The next expression forces a loop to immediately skip to its next iteration, bypassing any subsequent code that makes up the remainder of the loop body. Control flow returns to the beginning of the loop expression.
#
# next.icn, Demonstrate the next emphatic reserved word expression
#
procedure main()
# displays 1, 3, 4
every i := 1 to 4 do {
if i = 2 then next
write(i)
}
# displays i 1,3,4 paired with inner j 1,3
every i := 1 to 4 do {
every j := 1 to 3 do {
# break out of the j loop and reiterate the i loop
if i = 2 then break next
# reiterate the j loop
if j = 2 then next
write("i: ", i, " j: ", j)
}
}
end
Giving:
prompt$ unicon -s next.icn -x
1
3
4
i: 1 j: 1
i: 1 j: 3
i: 3 j: 1
i: 3 j: 3
i: 4 j: 1
i: 4 j: 3
not¶
not expr reverses the success or failure status of expr.
Some care must be shown when using not
in Unicon. It is reversing the
sense of success and failure, not acting as a boolean operator as used with
most other programming languages. For instance:
not 1
Does not produce a zero, as might be assumed by a C programmer, it signals
failure, reversing the successful 1
result to fail.
See the bitwise functions iand, icom, ior, ishift, and ixor when bit twiddling is called for.
icom(i) would be the closest Unicon equivalent to not in most boolean value control flow languages.
not &fail
The code above will produce a successful &null result.
#
# not.icn, Demonstrate the success/failure reversal reserved word
#
procedure main()
# no write occurs, failure propogates
write(not 1)
a := not &fail
write("not &fail is ", image(a))
if not every 1 to 2 then write("turn every failure into success")
end
Giving:
prompt$ unicon -s not.icn -x
not &fail is &null
turn every failure into success
repeat¶
repeat expr
introduces and infinite loop of expr. It is up to an
element inside expr to exit the loop or terminate the program.
#
# repeat.icn, demonstrate the infinite repeat loop
#
procedure main()
i := 0
repeat {
i +:= 1
case i of {
2: next
4: break
}
write(i)
}
write("loop exited at ", i)
end
Sample run:
1
3
loop exited at 4
return¶
return [expr]
exits a procedure or method, producing expr as its
result. The invocation may not be resumed. Default value for the optional
expr is &null.
#
# return.icn, demonstrate how return terminates a generator
#
procedure main()
every write(r := subproc())
# set an exit code from last given result; 42
exit(r)
end
# generate sequence 1 to n, until the result of that sequence hits 3
procedure subproc()
suspend i := !seq() do {
if i = 3 then return 42
}
end
Sample run:
prompt$ unicon -s return.icn ; ./return ; echo "shell status: $?"
1
1
2
1
2
3
42
shell status: 42
suspend¶
suspend expr [ do expr1 ]
Suspend a value from a procedure. When resumed, the optional do expr1 will be evaluated before control passes to resumption point. If expr is a generator, resumption of the suspended procedure will resume the generator and suspend again with the result produced.
#
# suspend-sample
#
procedure main()
if susproc() == 5 then write("got 5") else write("no 5")
end
procedure susproc()
local val
suspend val := seq() do write("val was: ", val)
end
Sample run
prompt$ unicon -s -t suspend-sample.icn -x
: main()
nd-sample.icn: 12 | susproc()
nd-sample.icn: 17 | susproc suspended 1
nd-sample.icn: 12 | susproc resumed
val was: 1
nd-sample.icn: 17 | susproc suspended 2
nd-sample.icn: 12 | susproc resumed
val was: 2
nd-sample.icn: 17 | susproc suspended 3
nd-sample.icn: 12 | susproc resumed
val was: 3
nd-sample.icn: 17 | susproc suspended 4
nd-sample.icn: 12 | susproc resumed
val was: 4
nd-sample.icn: 17 | susproc suspended 5
got 5
nd-sample.icn: 13 main failed
thread¶
thread expr
is equivalent to spawn(create expr)
. Create a thread
and then start it running. The thread handle is produced, of type
Unicon Co-Expressions.
Threading in Unicon is a wide ranging topic, best described by the feature
author, Jafar Al-Gharaibeh, in Unicon technical report UTR14,
http://unicon.org/utr/utr14.pdf. This document is also shipped with the
Unicon sources as doc/utr/utr14.docx
A small producer/consumer example:
#
# thread.icn, Demonstrate thread messaging
#
# requires Concurrency build of Unicon
#
procedure main()
pTr := thread producerRace()
cTr := thread consumerRace(pTr)
every wait(pTr | cTr)
write("racing producer/consumer complete")
write()
pT := thread producer()
cT := thread consumer(pT)
every wait(pT | cT)
write("main complete")
end
#
# This code can easily trigger incorrect results due to a race condition
#
# send messages to the thread out-box
procedure producerRace()
write("producer entry")
every !6@>
end
# receive messages from the out-box of the producer thread
procedure consumerRace(T)
write("consumer entry")
while write(<@T)
end
# What follows is the suggested update from Jafar
# It alleviates the race condition where consumerRace
# can complete before the producerRace even starts
#
# an original capture:
#
# JMBPro:proj jafar$ ./thrd
# producer entry
# consumer entry
# racing producer/consumer complete
#
# This is the better code...
#
# send messages to the thread out-box
procedure producer()
write("synch producer entry")
every !6@>
# produce &null (&null@>) to signal the end
@>
end
# receive messages from the out-box of the producer thread
procedure consumer(T)
write("blocking consumer entry")
# blocking receive.
while write(\<<@T)
end
Sample run:
prompt$ unicon -s thread.icn -x
producer entry
consumer entry
1
2
3
4
5
6
racing producer/consumer complete
synch producer entry
blocking consumer entry
1
2
3
4
5
6
main complete
to¶
expr1 to expr2 [ by expr3 ] produces the integer sequence
from expr1 to expr2 with an optional step value given by expr3. The
default step is 1
.
The initial value of expr1 is always included in the sequence. The last result will be less than or equal to expr2, depending on the step size of expr3.
#
# to.icn, demonstrate to-by sequence generator
#
procedure main()
writes("1 to 3: ")
every writes((1 to 3) || " ")
writes("\n1 to 5 by 2: ")
every writes((1 to 5 by 2) || " ")
writes("\n1 to 6 by 2: ")
every writes((1 to 6 by 2) || " ")
writes("\n1 to 7 by 2: ")
every writes((1 to 7 by 2) || " ")
writes("\n3 to 1:")
every writes((3 to 1) || " ")
writes("\n3 to 1 by -1: ")
every writes((3 to 1 by -1) || " ")
write()
end
Giving:
prompt$ unicon -s to.icn -x
1 to 3: 1 2 3
1 to 5 by 2: 1 3 5
1 to 6 by 2: 1 3 5
1 to 7 by 2: 1 3 5 7
3 to 1:
3 to 1 by -1: 3 2 1
See also
until¶
until expr1 [ do expr2 ] loops until expr1 succeeds evaluating the optional expr2 after each test.
#
# until.icn, Demonstrate loop until success
#
procedure main()
i := 1
until i = 4 do {
write(i)
i +:= 1
}
end
Giving:
1
2
3
Declarative expressions¶
A fair number of the Unicon reserved words are of a declarative nature:
- informing the compiler how defined items are to be treated
- for the creation of program elements at compile time
- and other construction details.
abstract¶
A method attribute. Allows a class hierarchy to include methods that must be defined lower in the inheritance chain.
abstract methods have no implementation at the point of declaration. A sub-class is responsible for defining implementation code.
#
# abstract.icn, demonstrate an abstract method declaration
#
class animal(tag, position)
# all animals conceptually move by changing position
method moving(d)
position +:= d
write(tag, " moved to ", position)
end
# a generic animal needs a specific way of speaking
abstract method speak(words)
initially
position := 0
end
# the dog class
class dog : animal(tag)
method speak(words)
write("bark? woof? grr? eloquent soliloquy?")
end
end
# create a dog, move it and ask it to speak
procedure main()
fido := dog("fido")
fido.moving(4)
fido.speak()
end
Sample run:
fido moved to 4
bark? woof? grr? eloquent soliloquy?
See Unicon GUI by Robert Parlett for more practical examples of abstract
methods when designing graphical user interface hierarchies.
class¶
class name [: superclass :...](attributes)
is a Unicon object
programming declarative, defining name. name can then be used to create
instances of the class.
Class hierarchies are defined with an (optional) colon separated list of parent classes.
class
definitions include
class
definitions end with the end reserved word.
#
# class.icn, demonstrate a class declaration
#
# THIS CODE IS UNFINISHED BUSINESS
$define space ' '
class creator(field)
method show(f)
write(image(r := (\f | field)))
return r
end
end
procedure p()
r := "abc"
return r
end
procedure main()
c := creator("name")
write(type(c), " ", image(c))
a := c.show()
b := c.show('a')
pr := p()
write(image(a), space, image(b), space, image(pr))
end
#$include "abstract.icn"
Sample run:
creator__state object creator_1(1)
"name"
'a'
"name" 'a' "abc"
See abstract for more details on the code sample.
In Unicon, class
can be compared to record; declaring a name that
is used later to define storage. Object oriented programming is orders of
magnitude more powerful, encapsulating code along with the data values, all
within an inheritance hierarchy.
global¶
global var [, var...] declares one or more global variables. Placed outside of procedures, the named variables will be accessible inside all procedures and methods of the program.
#
# global.icn, demonstrate global variables
#
global var, other
procedure main()
var := other := 42
subproc()
# var will be changed, other will not
write(var)
write(other)
end
# access the global "var", but create a local "other"
procedure subproc()
local other
write(var)
var := 84
other := 21
end
Giving:
42
84
42
See also
import¶
import package [package...]
imports one or more packages. This is a
programming in the large Unicon feature. Using packages relies on an external
databases, uniclass
to help manage the namespace resolution.
#
# import.icn, demonstrate a package import
#
import example
procedure main()
example()
end
Sample run:
prompt$ unicon import.icn -x
Parsing import.icn: ..
/home/btiffin/unicon-git/bin/icont -c -O import.icn /tmp/uni84777349
Translating:
import.icn:
main
No errors
/home/btiffin/unicon-git/bin/icont import.u -x
Linking:
Executing:
in example procedure of example package
See also
invocable¶
invocable [all | name,...]
allow string invocation of the given
name(s), or any procedure with the all reserved word.
#
# invocable.icn, Demonstrate string invocation
#
# an alternative is invocable all to allow any string invocations
invocable "subproc"
procedure main()
# allowed
f := "subproc"
f(42)
# will cause a runtime error, not listed as invocable
f := "other"
f(42)
end
procedure subproc(in)
write("in subproc with: ", in)
end
procedure other(in)
write(in)
end
Sample run will end in a purposeful error, “other” is not set invocable.
prompt$ unicon -s invocable.icn -x
in subproc with: 42
Run-time error 106
File invocable.icn; Line 22
procedure or integer expected
offending value: "other"
Traceback:
main()
"other"(42) from line 22 in invocable.icn
link¶
link library [, library...]
links other ucode into this program.
Unicon ucode files are created with unicon -c source.icn
. This option
creates a library that can be linked into other programs.
The IPL provides hundreds of ready to link library procedures.
#
# link.icn, demonstrate Unicon link
#
# link in the reflective extended image function
link ximage
procedure main()
L := [1,2,3]
write("image of L:")
write(image(L))
write("\nximage of L:")
write(ximage(L))
end
Sample run:
prompt$ unicon -s link.icn -x
image of L:
list_1(3)
ximage of L:
L1 := list(3)
L1[1] := 1
L1[2] := 2
L1[3] := 3
prompt$ unicon -s -t link.icn -x
: main()
image of L:
list_1(3)
ximage of L:
link.icn : 21 | ximage(list_1 = [1,2,3],&null,&null)
ximage.icn : 201 | ximage returned "L1 := list(3)\n ..."
L1 := list(3)
L1[1] := 1
L1[2] := 2
L1[3] := 3
link.icn : 22 main failed
See also
local¶
local var [, var...]
declares one or more variable as being within
local scope of a procedure or method body.
#
# local.icn, demonstrate local override of global variables
#
global var
procedure main()
var := 42
subproc()
# var will not be changed
write("var in main: ", var)
end
# create a local "var", global var not normally accessible inside subproc
procedure subproc()
local var
var := 84
write("var in subproc: ", var)
end
Sample run:
var in subproc: 84
var in main: 42
method¶
method name
declares a method within a class. An object
oriented feature of Unicon.
#
# method.icn, demonstrate a class method definition
#
class sample()
method sample()
write("in sample of sample")
end
end
procedure main()
instance := sample()
instance.sample()
end
Sample run:
prompt$ unicon -s method.icn -x
in sample of sample
package¶
package name
declares the current source unit to be part of a package,
name
. This defines a namespace for all procedures within the package.
Package access uses the import reserved word.
Packages are a programming in the large feature of Unicon. Using packages
relies on an external database, uniclass
, that manages the namespace
resolution.
#
# package.icn, Demonstrate Unicon packages (poorly)
#
package example
procedure main()
write("part of package sample")
end
procedure example()
write("in example procedure of example package")
end
Giving:
prompt$ unicon package.icn
Parsing package.icn: package.icn is already in Package example
...main is already in Package example
example is already in Package example
/home/btiffin/unicon-git/bin/icont -c -O package.icn /tmp/uni17775373
Translating:
package.icn:
example__main
example__example
No errors
/home/btiffin/unicon-git/bin/icont package.u
Linking:
prompt$ unicon -c package.icn
Parsing package.icn: package.icn is already in Package example
...main is already in Package example
example is already in Package example
/home/btiffin/unicon-git/bin/icont -c -O package.icn /tmp/uni18966310
Translating:
package.icn:
example__main
example__example
No errors
See also
procedure¶
procedure name([parameter,...])
defines a procedure. The body of the
procedure continues until the end reserved word is encountered.
User defined procedures are semantically equivalent to built in functions; they always produce a value or fail. Results can be suspended, or returned.
#
# procedure.icn, demonstrate a Unicon procedure definition
#
# procedure bodies continue up until the mandatory end reserved word
procedure main(arglist)
write("All Unicon programs require a main procedure")
write()
write("This program was invoked by the operating system with:")
every write(!arglist)
# if the arglist is empty, subproc will not be called
subproc(\arglist[1])
end
procedure subproc(arg)
write("This procedure \"subproc\" was invoked with: ", arg)
end
Sample run:
prompt$ unicon -s procedure.icn -x Determination
All Unicon programs require a main procedure
This program was invoked by the operating system with:
Determination
This procedure "subproc" was invoked with: Determination
main¶
Unless compiled with -c
or similar, all Unicon programs require a
procedure main()
. The program will be given a list of command line
arguments, but that usage is optional.
procedure main() ... end
procedure main(arglist) ... end
Are both valid Unicon main procedures.
For any given program there can only be one main
. The operating system is
given a zero result, even if return is used at the end of main. Other
platform dependent status codes can be set with the exit function.
Error status will be set when the stop function is used or when an
unconverted runtime error abnormal end occurs.
record¶
record name(field,...)
defines a record constructor for name
with
one or more fields.
#
# record.icn, demonstrate record data
#
record sample(a, b, c)
procedure main()
R := sample(1, 2, 3)
write(R.a)
write(R.b)
write(R.c)
end
Giving:
1
2
3
Trivia: record
can be used to form the shortest known complete Unicon
program.
procedure main()
end
That is not the shortest valid program. This is:
record main()
The shortest known complete program.[5] It creates a record
constructor that just happens to provide the main
procedure, a required
element of all valid Unicon programs. When executed the program evaluates the
constructor expression, creating a record of type main
and terminates
normally.
[5] | From the Icon Newsletter, Programming Corner, Issue 32 (question), and 33 (answer). |
static¶
static var [, var...]
declares local procedure or method variables to
be persistent while still local. Values will be remembered between
invocations during the entire program execution.
#
# static.icn, demonstrate static variable declarations
#
procedure main()
localproc()
staticproc()
write()
localproc()
staticproc()
end
# a is reset on each invocation
procedure localproc()
/a := "initial value"
writes("enter localproc with a as ")
write(image(a))
a := "new value"
end
# a is remembered across each invocation
procedure staticproc()
static a
/a := "initial value"
writes("enter staticproc with a as ")
write(image(a))
a := "new value"
end
Giving:
prompt$ unicon -s static.icn -x
enter localproc with a as "initial value"
enter staticproc with a as "initial value"
enter localproc with a as "initial value"
enter staticproc with a as "new value"
Syntax reserved words¶
Unicon also includes a few reserved words that work together with some of the other Unicon action words and Declarative expressions words.
all¶
all is an optional clause for the invocable declarative. Used to allow string invocation and any user defined procedure or built-in function.
See invocable for more details.
by¶
by is an optional step value clause for the to expression.
See to for more details. The default by
step is 1
.
default¶
default specifies a default case for the case of
selection
expression.
See case for more details.
do¶
do is an optional clause to specify the expression to be executed for each iteration of a loop construct.
See every, suspend while for more details. And, yes,
suspend
counts as a looping construct.
else¶
else evaluates an alternative expr3 when an if expr1 fails to produce
a result. An else
clause is optional with an if
statement.
if
expr1 then
expr2 else
expr3
See: if, then for more details.