XML

kent logo

CO538 Anonymous Questions and Answers Keyword Index

This page provides a keyword index to questions and answers. Clicking on a keyword will take you to a page containing all questions and answers for that keyword, grouped by year.

To submit a question, use the anonymous questions page. You may find the keyword index and/or top-level index useful for locating past questions and answers.

Keyword reference for arrays

2012

Question 54 (2012):

Submission reference: IN2363

Is the following code correct?

    PROC monitor.2 ([]CHAN INT in?, ...)
      [SIZE in?]BOOL ok:
      ...
    :

Answer 54:

Good question! Sadly, the answer is (currently) no.

Classical occam, being targetted originally at embedded applications (which have finite non-expandable memory resources), was designed to enable the amount of memory needed by an application to be decided before the code was embedded in the target machine (i.e. at compile-time). This was to ensure that the application could not run out of memory at run-time (which would mean, possibly literally, a crash). A design constraint, therefore, was that arrays could only be declared with sizes known at compile time.

Your code is trying to declare an array with the (unspecified) size of an array parameter. Any sized array may be passed, so the compiler cannot determine a specific size and the declaration is, therefore, rejected.

occam-pi does support arrays whose size in not known at compile-time but, we're afraid, the syntax for this is different (and more complex) than the syntax for classical array declarations. This is because run-time sized arrays are supported only for mobile arrays (see slide 14 of "Mobiles etc."). Your declaration needs to be:

    PROC monitor.2 ([]CHAN INT in?, ...)
      INITIAL MOBILE []BOOL ok IS MOBILE [SIZE in?]BOOL:
      ...
    :

See the print.streams process declared in your starter files for exercises 3 and 4 (i.e. q3.occ and q4.occ) for a similar example of this.

Once declared as above, the mobile array is used with the same syntax for accessing its elements as the classical pre-sized arrays. It is our intention to rationalise the design of occam-pi (soon) so that mobile arrays and classical arrays are merged into one concept – so that the (very natural) declaration you tried is correct and the complex one above is abolished!

Note: mobility, as presented in the "Mobiles" slides, is not an examinable part of this module. Only some of its slides on barriers (154-161 and 165) are part of the presented material that is examinable (as noted in the Week 11 box of the Moodle page for this course).

Keywords: arrays , mobiles

2010

Question 69 (2010):

Submission reference: IN2030

Hiya, I have been going through the 2010 paper and have come stuck on question 3(a) where I have to write a function to count the TRUE elements in an array of bools, but the size of the bool array is not mentioned. How would I go about this?

Also, I noticed that in the answers page you have said that mobiles are not examinable, but there was a question on barriers. Are mobiles examinable this year??

Thanks :D

Answer 69:

The prefix SIZE operator returns the size of an array (of channels or any data-type). See slide 113 from the choice set of slides, 93 from replicators, 71 from shared-etc and Question 52 (2003) and Question 58 (2000) from the anonymous Q&As (which I found by searching for "SIZE" under the keyword-index page for "arrays" – I've now added a page for the keyword "size"). There's also an example in the very last code box of the occam reference/checklist (which is linked from the Practical Resources box on the Co538 Moodle page).

Note that this last example (from the reference/checklist) has very similar form to the answer required for the exam question part you raised. The answer to that part is trivial:

  INT FUNCTION count.true (VAL []BOOL array) 
    INT count: 
    VALOF 
      SEQ                  -- function body
        count := 0 
        SEQ i = 0 FOR SIZE array 
          IF 
            array[i] 
              count := count + 1 
            TRUE 
              SKIP
      RESULT count
  :

(where you only had to write the 8 lines starting from the line commented "function body").

I can't find anything in the answers page for this year that says there was a question on barriers? Please mail me (phw@kent.ac.uk) where you have seen this.

The concept of barrier synchronisation has been explained in previous exam questions (see Question 62 (2008)), with follow-on parts asking for bits of implementation and/or use. Such questions – introducing new concepts – are always possible. However, the formal occam-pi language mechanism for BARRIERs, along with that for MOBILEs, is presented in the slides titled mobiles. The material in the mobiles slides is for advanced study and is not examinable in Co538. The material in all the other slide sets (including shared-etc) is examinable.

Keywords: arrays , size

2009

Question 29 (2009):

Submission reference: IN1828

I've added the following output channel to the philosopher: CHAN PHIL.STATE report! PHIL.STATE has been defined as a CASE protocol. secure.college outputs an array of this particular protocol type to the display method. This is defined in the secure.college header like so:

    CHAN [n.philosophers]PHIL.STATE phil.out!

However, when attempting to assign each philosopher in the replicated PAR to a particular point in this array I get an error: "phil.out subscripted too many times". I am assigning it as follows:

    philosopher (i, left[i]!, right[i]!, down[i]!, up[i]!, phil.out[i]!)

What does this error mean? Am I doing something completely wrong?

Answer 29:

Your declaration of the channel array phil.out is wrong. You have declared a single channel that carries an array of PHIL.STATE messages (in each message):

    CHAN [n.philosophers]PHIL.STATE phil.out!

You need an array of channels, each one carrying a single PHIL.STATE in each message:

    [n.philosophers]CHAN PHIL.STATE phil.out!

Now, phil.out[i] references element i from the channel array. Before, phil.out was not an array, so adding the array subscript was an array subscript too many - as the error message says!

But there's something wrong with our compiler! occam-pi currently does not support the concept of an array of PHIL.STATE messages. On encountering your [n.philosophers]PHIL.STATE, the compiler should have thrown an error message of the form:

    Error-oc-charray.occ(line-number)- Name PHIL.STATE is not a TYPE

Investigating ...

Keywords: q7 , arrays , channels

2004

Question 120 (2004):

In occam, if I've got a BYTE array, I would have thought I could do something like this: (where "i" is an INT)

    array[5] := BYTE i

but it doesn't appear to work, can you explain why that is, when something such as this works perfectly fine: (where "b" is a BYTE).

    array[5] := b

Answer 120:

That should work fine, and does for me.. What error (exactly) are you getting ? Something else must be wrong..

Keywords: q7 , arrays

Referrers: Question 121 (2004)


Question 65 (2004):

I was looking through the questions on arrays and as you said arrays have to be of a fixed size and are not initialised by default. So how do you initialise them to be empty or the equivalent of java's null ? Also can arrays of a smaller size be assigned to a larger capacity array (assuming they are of the same type) ? For example:

    [num]BYTE temp := "":

does not work (and neither does ":= []")

Answer 65:

There is no concept of null in occam! There are no objects in occam!!

When we declare an occam array:

    [num]BYTE my.array:

This is (roughly) similar to declaring and constructing a Java array:

    byte[] myArray = new byte[num];

occam variables, including array variables, always refer to allocated space. Whether that space has defined values set in them is up to our program. No default values (e.g. zero) are set. To initialise array values, it's the same as in Java -- simply iterate over the elements, setting them in turn. For example:

    SEQ i = 0 FOR SIZE my.array
      my.array[i] := 0

[Aside: the statement above (that "occam variables ... always refer to allocated space") is strictly true for classical occam. The new occam-pi has mobile data types, space for which is dynamically allocated. So, mobile variables from time to time may not refer to allocated space. However, in that case, the occam-pi language rules (enforced by the compiler) do not allow us to attempt to access their values -- so there remains no concept of null (and null pointer error) that you can fall into, :).]

You can't assign a smaller array to a larger array -- or a larger array to a smaller one. The size of an array is part of that array's type in occam, so different sized arrays are not assignment compatible.

occam does however support something that helps here, that Java doesn't: array segments (someimes called slices -- see the last paragraph of section 5 in the "occam2 Checklist"). A segment expression allows a portion of an array to be used, instead of the whole array. For example:

      [my.array FROM 2 FOR 4] := "fred"

will assign those bytes to 4 bytes of `name', starting at index 2. It is the same as the code:

      VAL []BYTE tmp IS "fred"
      SEQ i = 2 FOR 4
	my.array[i] := tmp[i-2]

or:

      SEQ
	my.array[2] := 'f'
	my.array[3] := 'r'
	my.array[4] := 'e'
	my.array[5] := 'd'

but the segment expression is much more succinct. The other elements of my.array are untouched. Should the above my.array have less than (2 + 4) elements, of course there would be a range error.

Couple of other bits of syntax for these segment expressions: either the FROM part or the FOR part are optional -- but not both! The expression "[my.array FOR n]" means the first n elements of my.array (i.e. "[my.array FROM 0 FOR n]"). The expression "[my.array FROM m]" means the last m elements of my.array (i.e. "[my.array FROM m FOR (SIZE my.array) - m]").

If you want more (!) and like puzzles, check out Question 44 (2002).

Other things raised by your question. In occam, "" and [] represent an array of zero elements -- though these only have limited use. The new KRoC (occam-pi) now recognises `[]' as an empty array of any type ("" is specifically an zero-length array of BYTEs). These are useful as arguments to PROCs or FUNCTIONs that require array arguments, but the particular call does not need to pass any data.

Initialisation and declaration can be combined, but requires a slightly different syntax than what you've got above:

    INITIAL []BYTE name IS "fred":   -- declares and assigns a [4]BYTE array

The LHS and RHS types of the `IS' must match. But I doubt this will be useful here.

Keywords: arrays , array-segments

2003

Question 104 (2003):

I want to have an array of strings (which I have understood to be an array of bytes) but am unsure how to use this. Is it:

    [element_length][index_location]string_array:

And also how would I write into a specific location, e.g. put "hello world" into index `0' in the string array?

Answer 104:

You are along the right lines with your declaration. More correctly:

    [number.of.strings][string.length]BYTE string.array:

The important thing to remember (as was covered to some extent in `q6') is that occam does not have an explicit `string' type -- they're handled using arrays of BYTEs. Thus you need to cater for `string length' separately (or use `null'-padding on the strings).

The above declaration declares an array of arrays of BYTEs. In other words, an array of fixed-size strings. If all the strings are going to be constant, declare it as a VAL array, e.g.:

    VAL [][]BYTE string.array IS ["hello world   ",
                                  "from occam    ",
                                  "but not from C"]:

Note that all the `strings' are the same-length -- the compiler will reject the declaration if this is not the case.

If you go down the `variable' route, data can be placed in the array using standard assignment, but the types must match exactly -- `[4]BYTE' and `[6]BYTE' are different types, for example. Thus assignments will often end up using array slices. See Question 44 (2002) for a comprehensive description of these. E.g.:

    [10][20]BYTE string.array:
    SEQ
      [string.array[0] FOR 11] := "hello world"          -- type is [11]BYTE
      [string.array[0] FROM 11] := "         "           -- pad remaining BYTEs with spaces

or this could be done as a single assignment:

      string.array[0] := "hello world         "          -- type is [20]BYTE

Keywords: arrays , strings

Referrers: Question 40 (2011) , Question 33 (2006)


Question 69 (2003):

when a `[]BYTE' is first declared, is it initialised to "" ?

Answer 69:

No, but occam won't let you declare things like that. The following, for example, won't compile:

    []BYTE a:
    [0]BYTE b:
    SEQ
      ...

All array declarations must have a constant size:

    [42]BYTE a:
    [SIZE a]INT b:
    SEQ
      ...

The initial contents of arrays are undefined -- occam does not initialise them in any way. If you want them initialised, you must do it explicitly.

Keywords: arrays


Question 52 (2003):

How do we know/check if an array is empty ?

Answer 52:

The `SIZE' operator in occam will return the number of elements in an array. If zero, then you know the array is `empty' (or more correctly, zero-sized).

Unlike Java, there is no concept of null-ness in occam, and you can't declare sizeless arrays. Parameters are slightly different, you can have:

    PROC n.elements (VAL []INT array, INT count)
      count := SIZE array
    :

But not:

    PROC blah ()
      []INT array:
      SEQ
        ...  stuff
    :

occam will not let you declare a zero-sized array either, for example:

    PROC blog ()
      [0]INT array:
      SEQ
        ...  stuff
    :

Keywords: arrays , size

Referrers: Question 69 (2010)

2002

Question 44 (2002):

What do these mean??

  [array FROM s FOR 1][i]
  [[[array FROM s FOR 1] FOR i][j], 42]

Answer 44:

If X is an array, then X[i] refers to its ith. index element.

Well, [X FROM start FOR n] is an array - it represents the slice of the array X from index start for the next n elements inclusive. [This is explained in the last paragraph of Section 5 of "The occam Checklist" in your course notes.] Of course, if that slice takes us outside the index bounds of the array, that generates a run-time error.

So:

  [X FROM start FOR n][i]

is just the ith. index element of the array [X FROM start FOR n], which is the (start + i)th. index element of the array X, so long as i is in the bounds of [X FROM start FOR n] - i.e. so long as 0 <= i < n. Therefore:

  [array FROM s FOR 1][i]

is only legal if i is zero ... in which case it is the same as element array[s].

If start is zero, then [X FROM start FOR n] may be written as just [X FOR n]. So:

  [[array FROM s FOR 1] FOR i]

is only error free if i is zero or one. If the former, then the above represents a zero-length array for which any further indexing or slicing will throw a run-time error. If the latter, the above represents the same one-length array slice as before - i.e. it's the same as:

  [array FROM s FOR 1]

Continuing with the only legal assumption (that i is one), then:

  [[array FROM s FOR 1] FOR i][j]

equals:

  [array FROM s FOR 1][j]

As considered before, the above is only legal if j is zero, in which case it equals:

  array[s]

So, the original expression:

  [[[array FROM s FOR 1] FOR i][j], 42]

is only legal if i is one and j is zero - in which case, it equals:

  [array[s], 42]

So long as s is a legal index of the array array, this is a literal expression of either a two-element array (assuming that array is an array if integers) or a two-field RECORD type. See the answer to Question 45 (2002) for (non-examinable) information on RECORD types.

I'd not ask anyone to work through such a tortuous example in an exam!

Keywords: arrays , array-segments

Referrers: Question 65 (2004) , Question 104 (2003)

2000

Question 58 (2000):

Please could you type up the example on abbreviations you showed us in the lecture? They were on hand-drawn slides and about adding up elements of a 2-D array. Thanks.

Answer 58:

OK. Here's some code for adding up the elements of a 1-D array:

  SEQ
    sum := 0
    SEQ i = 0 FOR SIZE a
      sum := sum + a[i]

where a is an array of REAL64s (say) and sum is a single REAL64 variable.

Now, suppose a is a 2-D array of REAL64s and we need to add up each of its rows into corresponding elements of sum (which is now a 1-D array of REAL64s). The naive code, based on the above, would be:

  SEQ row = 0 FOR SIZE a
    SEQ
      sum[row] := 0
      SEQ col = 0 FOR SIZE a[row]
        sum[row] := sum[row] + a[row][col]

This code is correct but somewhat inefficient. Firstly, occam 2-D arrays live in a contiguous block of memory with all its rows having the same lengths (which is not the case for Java 2-D arrays). Therefore, it's slightly wasteful to look up the size of each row each time the inner loop starts. Instead, look this up once before doing anything else, give it a VAL name and use that name:

  VAL INT n.cols IS SIZE a[0]:
  SEQ row = 0 FOR SIZE a
    SEQ
      sum[row] := 0
      SEQ col = 0 FOR n.cols
        sum[row] := sum[row] + a[row][col]  -- innermost loop code

But the real inefficiency lies in the code of the innermost loop. That code is executed n.rows * n.cols times and involves calculating the addrresses of elements sum[row] and a[row][col]. The latter requires a multiplication and an addition - the former just an addition. Three run-time checks that row and col lie within their respective array index ranges may also be required (although a really clever optimiser may be able to deduce that they will always be within bounds and, therefore, omit these checks).

Compare the above with:

  VAL INT n.cols IS SIZE a[0]:
  SEQ row = 0 FOR SIZE a
    REAL64 sum.row IS sum[row]:             -- this is where we will do the sum
    VAL []REAL64 a.row IS a[row]:           -- this is what we are going to sum
    SEQ
      sum.row := 0
      SEQ col = 0 FOR n.cols
        sum.row := sum.row + a.row[col]     -- innermost loop code

Now, the innermost loop contains just one array reference, requiring only one addition for the address calculation and one range check on col (for which an optimiser does not have to be that clever to optimise away). Two new array references have been introduced in the abbreviations themselves - but these are not part of the innermost loop and only happen once per row. This code will execute much faster than the previous version.

The other benefit from introducing those abbreviations is that the inner code:

    SEQ
      sum.row := 0
      SEQ col = 0 FOR n.cols
        sum.row := sum.row + a.row[col]     -- innermost loop code

is as simple as the 1-D array summing code with which we started:

Keywords: abbreviation , arrays , size

Referrers: Question 69 (2010)

Valid CSS!

Valid XHTML 1.0!

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.
Last modified Mon May 20 13:50:25 2013
This document is maintained by Fred Barnes, to whom any comments and corrections should be addressed.