Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Language Atlas (mini-courses for more languages)  Module 5 – Ada with Alire and GNAT

Ada for C and Java developers: strong types

Map C and Java habits to Ada: integer types with ranges, Constraint_Error, rem and mod, arrays that keep their bounds, reductions and parameter modes.

  • Beginner
  • 15 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Java temurin-25.0.4+101.0.LTS, Clang 21.0.0, Alire 2.1.1 and GNAT 16.1.0
  • By MySmartCoPilot
Free lesson, Pro answers: 15 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Declare integer types and subtypes with ranges, and predict when a value raises Constraint_Error
  • Predict what /, rem and mod give for negative numbers in Ada, C and Java, and what an overflow does in each
  • Use arrays indexed by any range and their attributes First, Last, Length, Range and Image
  • Use an Ada 2022 reduction expression to sum an array, and choose a type for its accumulator
  • Split code into a package specification and body, and return results through out and in out parameters

Before you start

What you’ll learn · Before you start

What you will learn

  • Declare integer types and subtypes with ranges, and predict when a value raises Constraint_Error
  • Predict what /, rem and mod give for negative numbers in Ada, C and Java, and what an overflow does in each
  • Use arrays indexed by any range and their attributes First, Last, Length, Range and Image
  • Use an Ada 2022 reduction expression to sum an array, and choose a type for its accumulator
  • Split code into a package specification and body, and return results through out and in out parameters

Before you start

On this page

In Java Integer.MAX_VALUE + 1 is −2,147,483,648, and nothing reports it. In Ada Integer'Last + 1 raised Constraint_Error, and so did storing 103 in a variable whose type allows marks from 0 to 100: a type in Ada says which values it may hold, and the compiler and the running program hold it to that.

This lesson maps what you write in C and Java onto Ada, one difference at a time, each shown by a recorded run: integer types with their own ranges, the three division operators, arrays that keep their bounds, the reductions of Ada 2022, and packages whose parameters say which way data flows.

A type says which values it may hold

In C a mark is an int, and the C standard says a typedef introduces no new type, only a synonym; in Java it is an int as well. In Ada type Mark is range 0 .. 100; declares a new integer type, and the Reference Manual says the declaration also defines its first subtype, constrained to those bounds. A An Ada subtype is a type with an extra constraint, such as a narrower range: values of the subtype are values of its type, and can be mixed with them, but storing one outside the constraint is checked. narrows a type without making a new one: subtype Pass_Mark is Mark range 40 .. 100;. This program reads marks from its command line and adds 5 grace marks to each:

marks.adb: a type, a subtype and a range check ADB · types/src/marks.adb
with Ada.Command_Line; use Ada.Command_Line;
with Ada.Exceptions;   use Ada.Exceptions;
with Ada.Text_IO;      use Ada.Text_IO;

procedure Marks is
   type Mark is range 0 .. 100;
   subtype Pass_Mark is Mark range 40 .. 100;

   Grace : constant Mark := 5;
   Given : Mark;
begin
   Put_Line ("Mark is" & Mark'First'Image & " .." & Mark'Last'Image
             & ", Mark'Base is " & Mark'Base'First'Image & " .."
             & Mark'Base'Last'Image);
   for I in 1 .. Argument_Count loop
      Put (Argument (I));
      begin
         Given := Mark'Value (Argument (I));
         Put (if Given in Pass_Mark then " is a pass" else " is below 40");
         Put (", plus grace" & Mark'Image (Given + Grace));
         Given := Given + Grace;
         Put_Line (", stored");
      exception
         when E : Constraint_Error =>
            Put_Line (", Constraint_Error, " & Exception_Message (E));
      end;
   end loop;
end Marks;

The session runs it on five arguments, then builds a version in which two lines break the rules:

Five marks, then two lines the compiler refuses Python · types_session.py
from session import run

# marks.adb on five arguments, from a pass to text that is not a number; then the version in wrong/, which mixes a
# Mark with a Paise and gives a Pass_Mark the value 35, built in its place.
run("""
cd types
alr build
./bin/marks 72 38 98 101 abc
cp ../wrong/marks.adb src/marks.adb
!alr build
""")

Output

$ cd types
$ alr build
Note: Synchronizing workspace...
Nothing to update.

Note: Building types=0.1.0-dev/types.gpr...
Setup
   [mkdir]        object directory for project Types
   [mkdir]        exec directory for project Types
Compile
   [Ada]          marks.adb
Bind
   [gprbind]      marks.bexch
   [Ada]          marks.ali
Link
   [link]         marks.adb
Success: Build finished successfully in … seconds.
$ ./bin/marks 72 38 98 101 abc
Mark is 0 .. 100, Mark'Base is -128 .. 127
72 is a pass, plus grace 77, stored
38 is below 40, plus grace 43, stored
98 is a pass, plus grace 103, Constraint_Error, marks.adb:21 range check failed
101, Constraint_Error, marks.adb:18 range check failed
abc, Constraint_Error, bad input for 'Value: "abc"
$ cp ../wrong/marks.adb src/marks.adb
$ alr build
Note: Building types=0.1.0-dev/types.gpr...
Compile
   [Ada]          marks.adb
marks.adb:10:35: error: invalid operand types for operator "+"
marks.adb:10:35: error: left operand has type "Paise" defined at line 6
marks.adb:10:35: error: right operand has type "Mark" defined at line 4
marks.adb:11:35: warning: value not in range of type "Pass_Mark" defined at line 5 [enabled by default]
marks.adb:11:35: warning: Constraint_Error will be raised at run time [enabled by default]

   compilation of marks.adb failed

gprbuild: *** compilation phase failed
ERROR: Command ["gprbuild", "-s", "-j0", "-p", "-P", "types/types.gpr"] exited with code 4
ERROR: Compilation failed.
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 types_session.py

72 and 38 behave as in any language. Mark'Value ("101") stopped with Constraint_Error: The predefined Ada exception raised when a value leaves the range of its subtype or the base range of its type, when an array index is out of bounds, or when an integer is divided by zero., range check failed, because 101 is not a Mark, and abc with bad input for 'Value. The surprise is 98. The program printed the sum 103 and only then failed, on the line that stores it. Arithmetic on a Mark happens in Mark'Base, the base range: The range an Ada integer type's arithmetic works in, chosen by the compiler to include at least the declared range and to be symmetric about zero: -128 .. 127 for a type declared 0 .. 100 with GNAT 16. the compiler picks for the type, which the program printed as −128 .. 127, and Mark'Image takes any value of Mark'Base, so printing 103 checks nothing. Storing it in Given is where the range check runs. Step through the three sums of this lesson and the check each one meets:

Interactive · stage by stage When Ada checks the value of a Mark Step through three sums from the lesson's runs and see which check each one meets, and where.
When Ada checks the value of a Mark, step 6 of 6. Showing Add in Mark'Base, Inside Mark'Base? (fails for 167), Use the result (an Image prints it), Store it in a Mark, Inside 0 .. 100? (fails for 103), Value kept. In focus: Inside Mark'Base?, Inside 0 .. 100?.overflow check failsrange check failsAdd in Mark'BaseGNAT: -128 .. 127Inside Mark'Base?fails for 167Use the resultan Image prints itStore it in a Markassignment, parameterInside 0 .. 100?fails for 103Value keptGiven now holds it

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Sums happen in the base type. Given + Grace is computed in Mark'Base, the range the compiler chose for the type's arithmetic. The program printed it: Mark'Base is -128 .. 127, eight bits, though a Mark only allows 0 .. 100.
  2. 72 plus 5. The sum 77 is inside -128 .. 127, so the overflow check passes, and it is also inside 0 .. 100, so storing it in Given passes the range check. The run printed 72 is a pass, plus grace 77, stored.
  3. 98 plus 5, printed. The sum 103 fits the base range, so no overflow check fails. Mark'Image takes a value of Mark'Base, so it printed 103 without any range check.
  4. 98 plus 5, stored. Given := Given + Grace stores 103 in a Mark. Here the range check runs, and 103 is not in 0 .. 100: Constraint_Error, marks.adb:21 range check failed.
  5. 72 plus 95. In totals.adb the reduction adds 72 and 95 in a Mark accumulator. 167 does not even fit -128 .. 127, so the overflow check fails first: Constraint_Error, overflow check failed.
  6. Two checks, two places. The overflow check guards every operation, against the base range; the range check guards every store into a subtype, against its own range. Both raise Constraint_Error, and the message says which one failed.

The version in wrong/ did not compile at all. Fee + Maths adds a Paise to a Mark, and GNAT refused it with invalid operand types for operator "+", naming both types; to mix them you convert one explicitly, as in Paise (Maths). And Lowest : constant Pass_Mark := 35; was caught before the program ever ran: the compiler warned that the value is not in the range of Pass_Mark and that Constraint_Error will be raised at run time.

Expecting a range check on every expression

Put_Line (Mark'Image (Given + Grace)) printed 103 for a Mark of 98. Checks run when a value is stored, passed as a parameter or converted, and the base range guards the arithmetic in between. Store the result in a Mark, or write Mark (Given + Grace), when it must be a Mark.

Checkpoint

Check: Integer types, subtypes and Constraint_Error

  1. Question 1 of 2 Given is a Mark (0 .. 100) holding 98. What happens on Put_Line (Mark'Image (Given + 5)); followed by Given := Given + 5;?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: The first line prints 103; the second raises Constraint_Error, range check failed

    Ada checks a value against a subtype's range when it is stored, passed or converted, and checks arithmetic against the base range. Between the two, an expression may hold a value its type does not allow.

  2. Question 2 of 2 Fee is a Paise and Maths is a Mark, two integer types of their own. What does GNAT say about Fee + Maths?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: invalid operand types for operator "+", naming both types

    Distinct integer types let the compiler stop a whole class of mix-ups, such as adding marks to money, before the program runs.

Division truncates as in C and Java, while mod follows the divisor

Ada has three operators where C and Java have two. The Reference Manual defines / and rem by the relation A = (A/B)*B + (A rem B), where A rem B has the sign of A, and it defines mod so that the result is zero or has the sign of B. Here they are on the four combinations of signs, followed by 18 % of 1,003 rupees in whole rupees and one more than Integer'Last:

arith.adb: the signs of /, rem and mod, and an overflow ADB · arith/src/arith.adb
with Ada.Exceptions; use Ada.Exceptions;
with Ada.Text_IO;    use Ada.Text_IO;

procedure Arith is

   function Cell (N : Integer) return String is
      Image : constant String := N'Image;
   begin
      return (1 .. 5 - Image'Length => ' ') & Image;
   end Cell;

   type Pair is record
      A, B : Integer;
   end record;

   Pairs : constant array (1 .. 4) of Pair :=
     [(7, 2), (-7, 2), (7, -2), (-7, -2)];
   Price : constant Natural := 1_003;
   Big   : Integer := Integer'Last;
begin
   Put_Line ("    A    B  A/B  rem  mod");
   for P of Pairs loop
      Put_Line (Cell (P.A) & Cell (P.B) & Cell (P.A / P.B)
                & Cell (P.A rem P.B) & Cell (P.A mod P.B));
   end loop;
   Put_Line ("18% of" & Price'Image & " with /:"
             & Natural'Image (Price * 18 / 100));
   Put_Line ("Rounded half up, (x + 50) / 100:"
             & Natural'Image ((Price * 18 + 50) / 100));
   Big := Big + Integer'Value ("1");
   Put_Line ("Never printed:" & Big'Image);
exception
   when E : Constraint_Error =>
      Put_Line ("Integer'Last + 1: Constraint_Error, "
                & Exception_Message (E));
end Arith;

This crate has two programs, so the session builds it with alr build -- -j1: whatever follows -- goes to GPRbuild, and -j1 makes it work on one file at a time, so its progress lines come in the same order on every run.

The four signs, 18 % of 1,003 rupees, Integer'Last + 1 and the paise amounts Python · arith_session.py
from session import run

# The four signs of / rem and mod, 18 % of 1003 rupees in whole rupees, one more than Integer'Last, and the paise
# amounts that the lesson's exercise models. The crate has two programs, so GPRbuild gets -j1 after --: one job at a
# time, and its progress lines come in the same order on every run.
run("""
cd arith
alr build -- -j1
./bin/arith
./bin/rupees 1205 99 100000 5 0
""")

Output

$ cd arith
$ alr build -- -j1
Note: Synchronizing workspace...
Nothing to update.

Note: Building arith=0.1.0-dev/arith.gpr...
Setup
   [mkdir]        object directory for project Arith
   [mkdir]        exec directory for project Arith
Compile
   [Ada]          arith.adb
   [Ada]          rupees.adb
Bind
   [gprbind]      arith.bexch
   [Ada]          arith.ali
   [gprbind]      rupees.bexch
   [Ada]          rupees.ali
Link
   [link]         arith.adb
   [link]         rupees.adb
Success: Build finished successfully in … seconds.
$ ./bin/arith
    A    B  A/B  rem  mod
    7    2    3    1    1
   -7    2   -3   -1    1
    7   -2   -3    1   -1
   -7   -2    3   -1   -1
18% of 1003 with /: 180
Rounded half up, (x + 50) / 100: 181
Integer'Last + 1: Constraint_Error, arith.adb:30 overflow check failed
$ ./bin/rupees 1205 99 100000 5 0
1205 paise = Rs 12.05
99 paise = Rs 0.99
100000 paise = Rs 1000.00
5 paise = Rs 0.05
0 paise = Rs 0.00

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 arith_session.py

The same divisions in Java and C, run on their own toolchains:

The same divisions in Java, with Math.floorMod Java · java/Division.java
public class Division {
  public static void main(String[] args) {
    int[][] pairs = {{7, 2}, {-7, 2}, {7, -2}, {-7, -2}};
    System.out.println("    a    b  a/b  a%b  floorMod");
    for (int[] p : pairs) {
      System.out.printf(
          "%5d%5d%5d%5d%5d%n", p[0], p[1], p[0] / p[1], p[0] % p[1], Math.floorMod(p[0], p[1]));
    }
    int price = 1003;
    System.out.println("18% of " + price + " with /: " + price * 18 / 100);
    int big = Integer.MAX_VALUE;
    big = big + 1;
    System.out.println("Integer.MAX_VALUE + 1 = " + big);
    int[] marks = {72, 95, 38, 48};
    try {
      System.out.println("marks[4] = " + marks[4]);
    } catch (ArrayIndexOutOfBoundsException e) {
      System.out.println("marks[4]: " + e.getMessage());
    }
  }
}

Output

    a    b  a/b  a%b  floorMod
    7    2    3    1    1
   -7    2   -3   -1    1
    7   -2   -3    1   -1
   -7   -2    3   -1   -1
18% of 1003 with /: 180
Integer.MAX_VALUE + 1 = -2147483648
marks[4]: Index 4 out of bounds for length 4

Recorded with OpenJDK 25.0.4.1 LTS (Eclipse Temurin) on macOS 26 arm64. To run it yourself: java Division.java

The same divisions in C C · c/division.c
#include <stdio.h>

int main(void) {
  int pairs[4][2] = {{7, 2}, {-7, 2}, {7, -2}, {-7, -2}};
  printf("    a    b  a/b  a%%b\n");
  for (int i = 0; i < 4; i++) {
    int a = pairs[i][0], b = pairs[i][1];
    printf("%5d%5d%5d%5d\n", a, b, a / b, a % b);
  }
  int price = 1003;
  printf("18%% of %d with /: %d\n", price, price * 18 / 100);
  return 0;
}

Output

    a    b  a/b  a%b
    7    2    3    1
   -7    2   -3   -1
    7   -2   -3    1
   -7   -2    3   -1
18% of 1003 with /: 180

Recorded with Apple clang version 21.0.0 (clang-2100.3.34.2) on macOS 26 arm64. To run it yourself: clang -std=c23 -O2 -Wall -Wextra -Werror -pedantic -fsanitize=address,undefined division.c -o division && ./division

Expression Ada C Java
−7 divided by 2 -7 / 2 = −3 -7 / 2 = −3 -7 / 2 = −3
remainder, sign of the dividend -7 rem 2 = −1 -7 % 2 = −1 -7 % 2 = −1
remainder, sign of the divisor -7 mod 2 = 1 no operator Math.floorMod(-7, 2) = 1
one more than the largest int Constraint_Error undefined behaviour wraps to −2,147,483,648

All three languages use truncating division: Integer division that drops the fraction, rounding towards zero, so -7 divided by 2 gives -3. C, Objective-C and Visual Basic's \ divide this way, and their remainder takes the dividend's sign. More in “A one-week plan for learning any language”: C’s standard calls the result the algebraic quotient with any fractional part discarded, and the Java Language Specification says integer division rounds toward 0. They part company on overflow. The Java specification says the integer operators do not indicate overflow in any way, and the C standard leaves the behaviour undefined; in Ada the Reference Manual raises Constraint_Error for an operation that cannot deliver the correct result within the base range, and the GNAT User’s Guide says overflow checking is on by default. The run said so: arith.adb:30 overflow check failed.

GST in whole rupees

Whole-number tax shows why the division rule matters. 18 % GST on ₹1,003 is ₹180.54, and 1003 * 18 / 100 drops the fraction, so the Ada, C and Java programs all printed 180; a bill that must round half up adds 50 before dividing and gets 181.

Rounding Calculator Round 180.54 with half up and with truncation to see 181 and 180 side by side.

Key idea

Ada’s / and rem truncate like / and % in C and Java; mod takes the divisor’s sign like Java’s Math.floorMod; and an integer overflow raises Constraint_Error instead of wrapping.

Checkpoint

Check: /, rem and mod, and overflow, against C and Java

  1. Question 1 of 2 What is 7 mod -2 in Ada?

    Type a number.

    A hint

    The result of mod is zero or has the sign of the divisor.

    Show the answer: Question 1 of 2

    Answer: -1 result

    The row 7, -2 of the arith.adb table printed /, rem and mod as -3, 1 and -1: rem keeps the sign of 7, mod the sign of -2. Java's Math.floorMod(7, -2) gives -1 too.

  2. Question 2 of 2 X holds Integer'Last in Ada, and x holds Integer.MAX_VALUE in Java. Each program adds 1. What do they do?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Ada raises Constraint_Error, overflow check failed; Java stores -2147483648 and carries on

    In C the same overflow is undefined behaviour; in Ada it is a check, on by default in GNAT.

An array keeps its bounds, and they can be any range

A C array starts at 0 and does not know its own length; a Java array starts at 0 and knows it. An Ada array type names its index type, so an array can start at 1, at roll number 101 or at Monday, and it carries its bounds with it. The A property of a type or an object, written with an apostrophe after its name, such as Class'First, Class'Length or Mark'Image. 'First, 'Last, 'Length and 'Range read them, so a loop never needs a separate count:

bounds.adb: three arrays, their bounds and an index past the end ADB · arrays/src/bounds.adb
with Ada.Exceptions; use Ada.Exceptions;
with Ada.Text_IO;    use Ada.Text_IO;

procedure Bounds is
   type Mark is range 0 .. 100;
   type Weekday is (Mon, Tue, Wed, Thu, Fri);
   type Scores is array (Positive range <>) of Mark;

   Class   : constant Scores (1 .. 4) := [72, 95, 38, 48];
   By_Roll : constant array (101 .. 104) of Mark := [72, 95, 38, 48];
   Present : constant array (Weekday) of Natural := [38, 40, 39, 36, 40];
   Seat    : constant Positive := Positive'Value ("5");
begin
   Put_Line ("Class'First =" & Class'First'Image & ", Class'Last ="
             & Class'Last'Image & ", Class'Length =" & Class'Length'Image);
   Put_Line ("By_Roll'First =" & By_Roll'First'Image & ", By_Roll'Last ="
             & By_Roll'Last'Image);
   for Roll in By_Roll'Range loop
      Put_Line ("  roll" & Roll'Image & ":" & By_Roll (Roll)'Image);
   end loop;
   for Day in Present'Range loop
      Put_Line ("  " & Day'Image & ":" & Present (Day)'Image & " present");
   end loop;
   Put_Line ("Class'Image:" & Class'Image);
   Put_Line ("Class (5) is" & Class (Seat)'Image);
exception
   when E : Constraint_Error =>
      Put_Line ("Class (5): Constraint_Error, " & Exception_Message (E));
end Bounds;
Bounds, an index past the end, two reductions and a misplaced 'Image Python · arrays_session.py
from session import run

# Arrays that carry their bounds, an index one past the end, two reductions of the same marks, and the version in
# wrong/ that applies 'Image to a reduction expression directly. -j1, after --, builds the two programs one at a time.
run("""
cd arrays
alr build -- -j1
./bin/bounds
./bin/totals
cp ../wrong/totals.adb src/totals.adb
!alr build -- -j1
""")

Output

$ cd arrays
$ alr build -- -j1
Note: Synchronizing workspace...
Nothing to update.

Note: Building arrays=0.1.0-dev/arrays.gpr...
Setup
   [mkdir]        object directory for project Arrays
   [mkdir]        exec directory for project Arrays
Compile
   [Ada]          bounds.adb
   [Ada]          totals.adb
Bind
   [gprbind]      bounds.bexch
   [Ada]          bounds.ali
   [gprbind]      totals.bexch
   [Ada]          totals.ali
Link
   [link]         bounds.adb
   [link]         totals.adb
Success: Build finished successfully in … seconds.
$ ./bin/bounds
Class'First = 1, Class'Last = 4, Class'Length = 4
By_Roll'First = 101, By_Roll'Last = 104
  roll 101: 72
  roll 102: 95
  roll 103: 38
  roll 104: 48
  MON: 38 present
  TUE: 40 present
  WED: 39 present
  THU: 36 present
  FRI: 40 present
Class'Image:
[ 72,  95,  38,  48]
Class (5): Constraint_Error, bounds.adb:25 index check failed
$ ./bin/totals
Sum of 4 marks: 253
Mean, as / gives it: 63
Class'Reduce: Constraint_Error, totals.adb:14 overflow check failed
$ cp ../wrong/totals.adb src/totals.adb
$ alr build -- -j1
Note: Building arrays=0.1.0-dev/arrays.gpr...
Compile
   [Ada]          totals.adb
totals.adb:9:61: error: prefix of attribute must be a name
totals.adb:9:61: error: qualify expression to turn it into a name
gprbuild: *** compilation phase failed
ERROR: Command ["gprbuild", "-s", "-j0", "-p", "-P", "arrays/arrays.gpr", "-j1"] exited with code 4
ERROR: Compilation failed.
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 arrays_session.py

The program’s first part printed the bounds of three arrays:

Attribute Class (1 .. 4) By_Roll (101 .. 104) Present (Weekday)
'First 1 101 MON
'Last 4 104 FRI
'Length 4 4 5
for I in X'Range 1, 2, 3, 4 101 … 104 MON … FRI

The weekdays printed in capitals because the Reference Manual makes the image of an enumeration value its identifier in upper case. Class'Image is new in Ada 2022: it printed the whole array as [ 72, 95, 38, 48], each element with the leading space of its own image, after a line break that the manual allows an implementation to add for readability. And Class (5) stopped with index check failed, where Java throws ArrayIndexOutOfBoundsException and in C reading past the end is undefined behaviour.

Loop over the array's own range

Write for I in Class'Range loop, or for M of Class loop when you need only the elements. The loop then follows the bounds when the array changes, and a slip like C’s i <= n cannot happen.

Checkpoint

Check: Arrays that keep their bounds

  1. Question 1 of 2 By_Roll is declared array (101 .. 104) of Mark. What do By_Roll'First and By_Roll'Length give?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: 101 and 4

    The attributes First, Last, Length and Range read an array's own bounds, so code that loops over X'Range works for any of them.

  2. Question 2 of 2 Class has the bounds 1 .. 4 and the program reads Class (5). What happens in Ada, and in C?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Ada raises Constraint_Error, index check failed; in C it is undefined behaviour

    Java would throw ArrayIndexOutOfBoundsException, as Division.java showed for marks[4].

’Reduce folds an array, and its accumulator’s type decides what fits

Summing marks is a loop in C and a stream in Java. Ada 2022 has reduction expression: An Ada 2022 expression with the attribute Reduce: it starts an accumulator at an initial value and combines it with each value in turn, so [for M of A => M]'Reduce ("+", 0) sums A.: the Reference Manual says one starts an accumulator at the initial value, then calls the reducer with the accumulator and each value in order, and yields the accumulator’s final value. totals.adb sums the same four marks twice:

totals.adb: two reductions of the same marks ADB · arrays/src/totals.adb
with Ada.Exceptions; use Ada.Exceptions;
with Ada.Text_IO;    use Ada.Text_IO;

procedure Totals is
   type Mark is range 0 .. 100;
   type Mark_List is array (Positive range <>) of Mark;

   Class : constant Mark_List := [72, 95, 38, 48];
   Sum   : constant Natural := [for M of Class => Natural (M)]'Reduce ("+", 0);
begin
   Put_Line ("Sum of" & Class'Length'Image & " marks:" & Sum'Image);
   Put_Line ("Mean, as / gives it:" & Natural'Image (Sum / Class'Length));
   declare
      Wrong : constant Mark := Class'Reduce ("+", 0);
   begin
      Put_Line ("Never printed:" & Wrong'Image);
   end;
exception
   when E : Constraint_Error =>
      Put_Line ("Class'Reduce: Constraint_Error, " & Exception_Message (E));
end Totals;

The second half of the session above ran it. The first reduction converts each mark to Natural and printed 253; the second, Class'Reduce ("+", 0), uses the "+" of Mark, so its accumulator is a Mark too. Step through both:

Interactive · step by step Two reductions of the same four marks Step through the accumulator of each reduction; watch its type, not only its value.
Two reductions of the same four marks, step 7 of 7. Showing Class (1) = 72, Class (2) = 95, Class (3) = 38, Class (4) = 48, Accumulator (a Mark: 167 fails). In focus: Class (2) = 95, Accumulator.Class (1) = 72Class (2) = 95Class (3) = 38Class (4) = 48Accumulatora Mark: 167 failsoverflow check failed

The drawing shows the whole scene; its 7 steps are listed below.

Every step as text
  1. The initial value. [for M of Class => Natural (M)]'Reduce ("+", 0) starts its accumulator at the initial value 0. Every value is converted to Natural first, so the accumulator is a Natural.
  2. First value. "+" is called with the accumulator and the first value: 0 + 72 = 72.
  3. Second value. 72 + 95 = 167. A Natural goes up to Integer'Last, 2147483647, so 167 is no trouble.
  4. Third and fourth values. 167 + 38 = 205 and 205 + 48 = 253, the value the program printed as the sum of 4 marks.
  5. The result. The reduction yields the accumulator's last value, 253; the program bound it to the constant Sum, and Sum / 4 gave a mean of 63.
  6. The same marks in a Mark. Class'Reduce ("+", 0) uses the "+" of Mark, so its accumulator is a Mark, starting at 0.
  7. The second value does not fit. 0 + 72 = 72, then 72 + 95 = 167, outside even Mark'Base, -128 .. 127: Constraint_Error, totals.adb:14 overflow check failed. The other two marks are never added.

The Mark accumulator failed at the second value: 72 + 95 is 167, outside Mark'Base, so the run printed overflow check failed, the check of the first section. The mean, Sum / Class'Length, printed 63, because 253 / 4 truncates 63.25. Choose the accumulator’s type for the total, not for the elements: a Natural holds the total of more than 21 million marks of 100.

The last two commands of the session built a version with a common slip: Put_Line ([for M of Class => Natural (M)]'Reduce ("+", 0)'Image);. GNAT refused it with prefix of attribute must be a name, because an attribute applies to a name and a reduction is an expression, and its second line names a fix, qualifying the expression with a type, as in Natural'(…)'Image. Binding the result to a constant first, as totals.adb does with Sum, works too and reads better.

Checkpoint

Check: Reduction expressions and their accumulator

  1. Question 1 of 2 Why did Class'Reduce ("+", 0) fail on the marks 72, 95, 38 and 48, while the reduction that converts each mark to Natural gave 253?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Its accumulator was a Mark, and 72 + 95 = 167 does not fit Mark'Base, -128 .. 127

    Give the accumulator a type that can hold the total, here Natural, by converting each value in the iterator: [for M of Class => Natural (M)]'Reduce ("+", 0).

  2. Question 2 of 2 GNAT rejects Put_Line ([for M of Class => Natural (M)]'Reduce ("+", 0)'Image);. Which change compiles?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Bind the reduction to a constant Sum and write Sum'Image

    The compiler's second line names the other fix: qualify the expression with a type, Natural'(…), which turns it into a name.

A package splits what callers may use from how it works

A C header lists functions, and a Java class marks members public or private. An Ada package does it in two files: the package specification: The part of an Ada package that other units may use, kept in a .ads file: its types, constants and subprogram declarations. The package body, in a .adb file, holds the code., grades.ads, lists what callers may use, and the body, grades.adb, holds the code. Each parameter states its parameter mode: The direction of an Ada parameter: in, the default, which the subprogram can only read; out, which brings a result back; or in out, which is read and written.. The Reference Manual makes in the default and a constant view, so the subprogram can only read it; out carries a result back to the caller; in out is read and written. So a procedure returns two results through out parameters without pointers, as Summary does:

A package specification, its body and a program that uses it

grades/src/grades.ads

package Grades is

   type Mark is range 0 .. 100;
   type Mark_List is array (Positive range <>) of Mark;

   function Passed (M : Mark) return Boolean is (M >= 40);

   procedure Add_Grace (M : in out Mark; By : Mark);
   --  Raise M by By marks, but never above 100.

   procedure Summary
     (List : Mark_List; Passes : out Natural; Best : out Mark);
   --  Count the marks of 40 or more, and find the highest.

end Grades;

grades/src/grades.adb

package body Grades is

   procedure Add_Grace (M : in out Mark; By : Mark) is
   begin
      M := (if M > Mark'Last - By then Mark'Last else M + By);
   end Add_Grace;

   procedure Summary
     (List : Mark_List; Passes : out Natural; Best : out Mark) is
   begin
      Passes := 0;
      Best := Mark'First;
      for M of List loop
         if Passed (M) then
            Passes := Passes + 1;
         end if;
         Best := Mark'Max (Best, M);
      end loop;
   end Summary;

end Grades;

grades/src/report.adb

with Ada.Text_IO; use Ada.Text_IO;
with Grades;      use Grades;

procedure Report is
   Class  : Mark_List := [72, 38, 98, 36];
   Passes : Natural;
   Best   : Mark;
begin
   Summary (Class, Passes, Best);
   Put_Line ("Before grace:" & Passes'Image & " passes, best" & Best'Image);
   for M of Class loop
      Add_Grace (M, By => 5);
   end loop;
   Summary (Class, Passes, Best);
   Put_Line ("After grace:" & Passes'Image & " passes, best" & Best'Image);
   Put_Line ("Class now:" & Class'Image);
end Report;
The report, then a body that writes to an in parameter Python · grades_session.py
from session import run

# A package with an in out and two out parameters, used by report.adb; then the body in wrong/, which assigns to an
# in parameter.
run("""
cd grades
alr build
./bin/report
cp ../wrong/grades.adb src/grades.adb
!alr build
""")

Output

$ cd grades
$ alr build
Note: Synchronizing workspace...
Nothing to update.

Note: Building grades=0.1.0-dev/grades.gpr...
Setup
   [mkdir]        object directory for project Grades
   [mkdir]        exec directory for project Grades
Compile
   [Ada]          report.adb
   [Ada]          grades.adb
Bind
   [gprbind]      report.bexch
   [Ada]          report.ali
Link
   [link]         report.adb
Success: Build finished successfully in … seconds.
$ ./bin/report
Before grace: 2 passes, best 98
After grace: 4 passes, best 100
Class now:
[ 77,  43,  100,  41]
$ cp ../wrong/grades.adb src/grades.adb
$ alr build
Note: Building grades=0.1.0-dev/grades.gpr...
Compile
   [Ada]          grades.adb
grades.adb:6:07: error: assignment to "in" mode parameter not allowed

   compilation of grades.adb failed

gprbuild: *** compilation phase failed
ERROR: Command ["gprbuild", "-s", "-j0", "-p", "-P", "grades/grades.gpr"] exited with code 4
ERROR: Compilation failed.
[exit status 1]

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 grades_session.py

Step through the calls of report.adb and watch which of its variables each mode lets a procedure change:

Interactive · step by step Which of the caller's variables a call may change Step through the calls of report.adb and watch which boxes each parameter mode lets the procedure write.
Which of the caller's variables a call may change, step 6 of 6. Showing Class ([77, 43, 100, 41]), Passes (4), Best (100), Summary, Add_Grace. In focus: Passes, Best.inoutoutin outClass[77, 43, 100, 41]Passes4Best100SummaryList : inAdd_GraceM : in out

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Before the calls. report.adb declares Class with four marks and two variables with no value yet, Passes and Best.
  2. An in parameter. Summary (Class, Passes, Best) passes Class as List, in mode, the default: the procedure may read it and the compiler rejects any assignment to it.
  3. Two out parameters. Passes and Best are out parameters: Summary writes them before it returns. The program printed before grace: 2 passes, best 98.
  4. An in out parameter. The loop for M of Class passes each mark to Add_Grace as M, in out: the procedure reads the mark and writes the new one back, 72 becoming 77.
  5. Every mark, capped at 100. After four calls the class holds 77, 43, 100 and 41: 98 + 5 would pass 100, so Add_Grace stored Mark'Last instead.
  6. Summary again. A second Summary call writes Passes and Best afresh: 4 passes, best 100.

Summary read the class and wrote two answers, 2 passes and best 98; the loop then passed each mark to Add_Grace in out, which capped 98 + 5 at Mark'Last, and the second summary found 4 passes and a best of 100. The broken body in wrong/ assigned to By, an in parameter, and GNAT refused it: assignment to "in" mode parameter not allowed. The mode is part of the contract a caller reads in the specification, so a C reader no longer has to guess whether a function writes through a pointer.

Key idea

The specification is all a caller sees, and its parameter modes say which way every value flows: an in parameter cannot be changed, an out parameter brings a result back, and an in out parameter does both.

Checkpoint

Check: Package specifications and parameter modes

  1. Question 1 of 2 Summary (List : Mark_List; Passes : out Natural; Best : out Mark) is called with Class, P and B. What may Summary do?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Read List, and write the results into P and B

    The modes in the specification tell the caller what a call may change without reading the body.

  2. Question 2 of 2 A procedure body contains By := 0;, where By is declared By : Mark with no mode. What happens?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: It does not compile: assignment to "in" mode parameter not allowed

    Copy the parameter into a local variable if the subprogram needs a value it can change.

Practise: compute as Ada does, in Python

The exercise ports this lesson’s arithmetic to Python, which divides the other way: Ada’s /, rem, mod, 'Image and the Rupees_Of function of rupees.adb, whose run printed 1205 paise = Rs 12.05. Its sample tests are the lines the lesson’s Ada programs printed, so a function that passes them reproduces Ada’s answers.

Exercise · Easy · Python

Compute as Ada does, in Python

You are porting an Ada report to Python and want Python to print exactly what the Ada program printed. Python's // and % round towards minus infinity, and str() adds no space, so write five small functions in ada_ops.py that work the way Ada does. The divisor b is never 0.

  • ada_div(a, b): Ada's a / b on integers, which drops the fraction, so -7 / 2 is -3.
  • ada_rem(a, b): Ada's a rem b, with the sign of a, so that a == ada_div(a, b) * b + ada_rem(a, b).
  • ada_mod(a, b): Ada's a mod b, zero or with the sign of b, so -7 mod 2 is 1 and 7 mod -2 is -1.
  • image(n): Ada's Integer'Image (n): the digits with a leading space when n is zero or more, and with a leading minus sign when it is negative.
  • rupees_of(paise): what the lesson's Rupees_Of returns for paise of zero or more: "Rs", the image of the whole rupees, a dot, and the last two digits of the image of 100 + paise rem 100. So 1205 paise is "Rs 12.05".

The sample tests are the lines that arith.adb and rupees.adb printed in the lesson's session.

Starter code · ada_ops.py

def ada_div(a, b):
    """Ada's a / b on integers."""
    return a // b  # Python rounds down; Ada drops the fraction


def ada_rem(a, b):
    """Ada's a rem b: the sign of a."""
    return a % b


def ada_mod(a, b):
    """Ada's a mod b: zero or the sign of b."""
    return a % b


def image(n):
    """Ada's Integer'Image (n)."""
    return str(n)


def rupees_of(paise):
    """What the lesson's Rupees_Of returns, for paise of zero or more."""
    return "Rs " + str(paise / 100)
The sample tests · test_ada_ops.py
from ada_ops import ada_div, ada_mod, ada_rem, image, rupees_of


def test_the_four_signs():
    """The table arith.adb printed: A, B, A/B, rem and mod"""
    rows = [(7, 2, 3, 1, 1), (-7, 2, -3, -1, 1), (7, -2, -3, 1, -1), (-7, -2, 3, -1, -1)]
    for a, b, quotient, remainder, modulus in rows:
        assert ada_div(a, b) == quotient
        assert ada_rem(a, b) == remainder
        assert ada_mod(a, b) == modulus


def test_the_identity():
    """a = (a / b) * b + (a rem b) for every sign, and mod differs from rem only across signs"""
    for a in (-9, -8, -1, 0, 1, 8, 9):
        for b in (-4, -3, 3, 4):
            assert a == ada_div(a, b) * b + ada_rem(a, b)
            m = ada_mod(a, b)
            assert m == 0 or (m > 0) == (b > 0)
    assert ada_mod(-9, 4) == 3
    assert ada_rem(-9, 4) == -1
    assert ada_mod(9, -4) == -3
    assert ada_mod(8, -4) == 0


def test_gst_in_whole_rupees():
    """18% of 1003 rupees with /, and rounded half up with (x + 50) / 100"""
    assert ada_div(1003 * 18, 100) == 180
    assert ada_div(1003 * 18 + 50, 100) == 181


def test_image():
    """Integer'Image puts a space before a number of zero or more"""
    assert image(2147483647) == " 2147483647"
    assert image(0) == " 0"
    assert image(-7) == "-7"
    assert image(-128) + " .." + image(127) == "-128 .. 127"


def test_rupees():
    """The five lines of ./bin/rupees 1205 99 100000 5 0"""
    assert rupees_of(1205) == "Rs 12.05"
    assert rupees_of(99) == "Rs 0.99"
    assert rupees_of(100000) == "Rs 1000.00"
    assert rupees_of(5) == "Rs 0.05"
    assert rupees_of(0) == "Rs 0.00"
A hint

Work with the sizes first: abs(a) // abs(b) is the size of Ada's quotient, and the quotient is negative exactly when a and b have different signs. rem then follows from a == quotient * b + rem, and mod differs from rem only when the two operands have different signs and the remainder is not 0.

The sample tests run on this device, in your browser (Pyodide): nothing is sent to mysmartcopilot.com. The first run downloads Python (about 13.5 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Big Number Calculator Add 1 to 2147483647 to see 2147483648, the value Java wraps to −2147483648 and Ada refuses to store.

Then check the five ideas of the lesson. The idea you have answered worst comes up first, and every choice explains itself as soon as you pick it:

Practice that adapts to you

Practise this lesson

12 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 12 What does Given in Pass_Mark test, where subtype Pass_Mark is Mark range 40 .. 100?

    Choose one answer.

    Show the answer: Question 1 of 12

    Answer: Whether Given lies in 40 .. 100

    Membership tests let you check a value against a range without risking an exception.

  2. Question 2 of 12 Lowest : constant Pass_Mark := 35; where Pass_Mark is 40 .. 100. When is the problem reported?

    Choose one answer.

    Show the answer: Question 2 of 12

    Answer: At compile time, as a warning that Constraint_Error will be raised at run time

    Read GNAT's warnings: one that says Constraint_Error will be raised is a bug found before the program ran.

  3. Question 3 of 12 A type Count is range 0 .. 200 is declared, and GNAT gives it an 8-bit base range, -128 .. 127, as it did for Mark. What happens when the program adds 1 to a Count holding 150?

    Choose one answer.

    Show the answer: Question 3 of 12

    Answer: That cannot happen: the base range must include 0 .. 200, so the compiler picks a wider one

    The base range is the compiler's choice within a rule: at least the declared range, symmetric about zero. For 0 .. 100, -128 .. 127 fits; for 0 .. 200 it does not.

  4. Question 4 of 12 What is -7 rem 2 in Ada?

    Type a number.

    Show the answer: Question 4 of 12

    Answer: -1 result

    rem has the sign of the dividend, -7, and (-7 / 2) * 2 + (-7 rem 2) = (-3) * 2 + (-1) = -7. C's -7 % 2 and Java's -7 % 2 are -1 too.

  5. Question 5 of 12 In whole rupees, what does Ada's 1003 * 18 / 100 give?

    Type a number.

    Show the answer: Question 5 of 12

    Answer: 180 rupees

    18,054 / 100 is 180.54, and / on integers drops the fraction: 180. Adding 50 first, (1003 * 18 + 50) / 100, rounds half up to 181.

  6. Question 6 of 12 A function moves a clock hand by Step minutes, Step possibly negative, and must return a minute from 0 to 59. Which expression is right in Ada?

    Choose one answer.

    Show the answer: Question 6 of 12

    Answer: (Minute + Step) mod 60

    Use mod when a result must stay in 0 .. N - 1 whatever the sign of the input, and rem when you want C's %.

  7. Question 7 of 12 Which loop visits every element of Present, an array indexed by Weekday (Mon .. Fri)?

    Choose one answer.

    Show the answer: Question 7 of 12

    Answer: for Day in Present'Range loop

    An array's index can be any discrete range, numbers or an enumeration, and 'Range always matches it.

  8. Question 8 of 12 What does Day'Image print for the Weekday value Mon?

    Choose one answer.

    Show the answer: Question 8 of 12

    Answer: MON

    Write a function that turns the image into the casing you want when the output is for people.

  9. Question 9 of 12 Sum is 253 and Class'Length is 4. What does Sum / Class'Length print?

    Type a number.

    Show the answer: Question 9 of 12

    Answer: 63 marks

    253 / 4 = 63.25, and integer / drops the fraction, so the run printed Mean, as / gives it: 63.

  10. Question 10 of 12 In [for M of Class => Natural (M)]'Reduce ("+", 0), what is the 0?

    Choose one answer.

    Show the answer: Question 10 of 12

    Answer: The initial value of the accumulator

    For a product you would start at 1: [for M of Class => Natural (M)]'Reduce ("*", 1).

  11. Question 11 of 12 You port a C function int parse(const char *text, int *value) that returns an error code and writes the parsed value through a pointer. What is the natural Ada specification?

    Choose one answer.

    Show the answer: Question 11 of 12

    Answer: procedure Parse (Text : String; Value : out Integer; Ok : out Boolean);

    Ada also lets you raise an exception for a parse error instead of returning a flag, which is what 'Value does for text that is not a number.

  12. Question 12 of 12 In which file does a caller find what package Grades lets it use?

    Choose one answer.

    Show the answer: Question 12 of 12

    Answer: grades.ads, the package specification

    Like a C header, but checked: the body must match the specification, or it does not compile.

Interview questions

Warm-up (fresher to mid-level): How do rem and mod differ in Ada, and which one matches C’s %?

Both give the remainder of an integer division; they differ only when the operands have different signs. A rem B has the sign of A, the dividend, and goes with Ada’s /, which truncates toward zero, so that A = (A / B) * B + (A rem B). A mod B is zero or has the sign of B, the divisor. So -7 rem 2 is −1 and -7 mod 2 is 1, while 7 rem -2 is 1 and 7 mod -2 is −1. C’s % and Java’s % behave like rem; Java’s Math.floorMod behaves like mod. Use mod when the result must stay in a range such as 0 to N − 1, a clock or a ring buffer, whatever the sign of the input, and rem when you want C’s behaviour.

Two questions that come up when C or Java code meets Ada:

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Fresher to senior

    You port a C function that computes a check digit from an account number's digits with / and %, including adjustments that can go negative. The Ada port agrees on most inputs but not all. Where do you look first, and how do you make the port provably match?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Fresher to senior

    A station timetable holds platform numbers, departure times as minutes past midnight and train numbers, all plain integers in the C code you inherit. Which Ada types do you declare, and how do you show a reviewer that a platform can no longer be passed where a time is expected?

    Model answer, Pro. First step and follow-ups

Flashcards · 8 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. What does type Mark is range 0 .. 100; give you that a C typedef does not?

    A new type, not a synonym: mixing a Mark with another integer type needs a conversion or the code does not compile, and storing 101 in a Mark raises Constraint_Error.

  2. A Mark of 98 gets 5 grace marks. Where does Ada's range check stop it?

    Only when 103 is stored in a Mark. The sum itself is computed in Mark'Base, −128 .. 127 with GNAT here, so printing it with Mark'Image showed 103.

  3. What are -7 / 2, -7 rem 2 and -7 mod 2 in Ada?

    −3, −1 and 1. As in C and Java, / and rem truncate; mod follows the sign of the divisor, as Java's Math.floorMod does.

  4. What does Integer'Last + 1 do in Ada, in Java and in C?

    Ada raises Constraint_Error, because GNAT checks overflow by default; Java silently wraps to −2,147,483,648; C leaves it undefined.

  5. How does Ada code read an array's bounds, and what happens at an index past the end?

    With 'First, 'Last, 'Length and 'Range, as in for I in Class'Range loop, so no separate count is needed. Class (5) on an array indexed 1 .. 4 stopped with index check failed.

  6. Why did Class'Reduce ("+", 0) fail on the marks 72 and 95?

    Its accumulator is a Mark, since it uses the "+" of Mark, and 72 + 95 = 167 is outside Mark'Base. Converting each mark to Natural first gave the total of all four, 253.

  7. What do the parameter modes in, out and in out let a procedure do with a value?

    in: only read it, and an assignment to it does not compile. out: hand a result back. in out: read it and write it. The mode is part of the specification a caller sees.

  8. How do an Ada package's specification and body divide the work?

    The specification, a .ads file, lists everything callers may use; the body, a .adb file, holds the code. Callers depend on the specification alone.

Key takeaways

  • type Mark is range 0 .. 100; makes a new type: mixing it with another integer type does not compile, storing 101 in it raises Constraint_Error, and its arithmetic runs in a wider base range, −128 .. 127 with GNAT here.
  • Ada’s / and rem truncate like C’s and Java’s / and %, mod takes the divisor’s sign, and an overflow raised Constraint_Error where Java wraps and C has undefined behaviour.
  • An array keeps its bounds: 'First, 'Last, 'Length and 'Range read them, an index past the end raised index check failed, and Ada 2022 can print a whole array with 'Image.
  • A reduction’s accumulator has a type of its own: summing in a Natural gave 253, while the Mark accumulator failed at 72 + 95.
  • A package specification lists what callers may use, and the parameter modes in, out and in out say which way each value flows; assigning to an in parameter does not compile.

Terms in this lesson

base range
The range an Ada integer type's arithmetic works in, chosen by the compiler to include at least the declared range and to be symmetric about zero: -128 .. 127 for a type declared 0 .. 100 with GNAT 16.
Constraint_Error
The predefined Ada exception raised when a value leaves the range of its subtype or the base range of its type, when an array index is out of bounds, or when an integer is divided by zero.
package specification
The part of an Ada package that other units may use, kept in a .ads file: its types, constants and subprogram declarations. The package body, in a .adb file, holds the code.
parameter mode
The direction of an Ada parameter: in, the default, which the subprogram can only read; out, which brings a result back; or in out, which is read and written.
reduction expression
An Ada 2022 expression with the attribute Reduce: it starts an accumulator at an initial value and combines it with each value in turn, so [for M of A => M]'Reduce ("+", 0) sums A.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.