Reserved words

_images/unicon.png

Index Unicon

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 next is not parsed as a new variable identifier, but is valid as the expr1 part of the assignment operator expr1 := expr2. Unicon accepts that code, which at runtime evaluates the next, as part of the assignment expression, immediately transferring control back to the top of the while loop; an infinite loop.

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

examples/break.icn

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

case expr of {
expr1: expr2
...
expr3: expr4
[default: exprn]
}

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

examples/case.icn

Sample run:

prompt$ unicon -s case.icn -x
"initial value"
"f"
"b"

See default, of.


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

examples/create.icn

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

examples/critical.icn

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

examples/every.icn

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

examples/every-filegen.icn

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

examples/fail.icn

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

examples/if.icn

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

examples/initial.icn

Giving:

bcd
"abc"
bcd
&null

See procedure, static.


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

examples/initially.icn

Giving:

Clinton L. Jeffery
Jane Doe
John Doe

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

examples/not.icn

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

examples/repeat.icn

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

examples/return.icn

Sample run:

prompt$ unicon -s return.icn ; ./return ; echo "shell status: $?"
1
1
2
1
2
3
42
shell status: 42

See also

procedure, method, suspend


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

examples/suspend-sample.icn

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

See also

every, repeat, until, while, break, next


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

examples/thread.icn

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

See also

create, spawn, wait


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

examples/to.icn

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

by


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

examples/until.icn

Giving:

1
2
3

See also

every, repeat, while, break, next


while

while expr1 [ do expr2 ] loops until expr1 fails, evaluating the optional expr2 after each test.

#
# while.icn, Demonstrate loop until fail
#
procedure main()
    i := 1
    while i < 4 do {
        write(i)
        i +:= 1
    }
end

examples/while.icn

Sample run:

1
2
3

See also

every, repeat, until, break, next


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

examples/abstract.icn

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"

examples/class.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

examples/global.icn

Giving:

42
84
42

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

examples/import.icn

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

package


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

examples/invocable.icn

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

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

examples/local.icn

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

examples/method.icn

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

examples/package.icn

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

import


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

examples/procedure.icn

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

examples/record.icn

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 

examples/static.icn

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.


end

end is the reserved word to signify the end of a class, method, or procedure body.


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.


of

of is the reserved word that precedes a special compound expression consisting of a sequence of case branches.

case expr of ...

See: case, default for more details.


then

then expressions are executed when (and only when) an if expr produces a result. The then reserved word is not optional when constructing a valid if expression.

See: if and else for more details.


Index | Previous: Operators | Next: Functions