tech days 2015: a quick tour of ada 2012
TRANSCRIPT
A quick tour of Ada 2012
Edmond SchonbergNovember 4, 2015
Ada 2012 has been here for 3 years !
The labor of a cast of thousands!
The latest in language design!
300 Ada Issues addressed! (and another 178 already created for Ada 2012)
For details: http://www.ada-auth.org and John Barnes book
For the gory details: http://www.ada-auth.org/standards/12aarm/html/AA-TTL.htmlFor the history of the gory details: http://www.ada-auth.org/AI05-SUMMARY.HTML
Highlights of Ada 2012
Program Correctness: programming by contract
• Pre- and Post-conditions for subprograms
• Type invariants, subtype predicates
– Iterators, generalized indexing and implicit dereference
– Bounded containers, proper concurrent queues, holder container
– Conditional and case expressions, expression functions
– Quantified expressions
– New concurrency constructs for multicores
– Better accessibility rules for anonymous access types
Program Correctness• Need a general mechanism to introduce new checkable properties of entities :
subprograms, types, subtypes.
• Checking may be static (compiler) or dynamic (assertions)
• RM 6.1.1 (AI05-0145) Pre- and Postconditions• RM 7.3.2 (AI05-0146) Type Invariants• RM 3.2.4 (AI05-0153) Subtype predicates
• One general syntactic mechanism for all of the above, and more:• RM 13.1.1 (AI05-0183) Aspect Specifications
Pre- and Postconditions generic type Item is private; package Stack_Interfaces is type Stack is interface; function Is_Empty (S : Stack) return Boolean is abstract; function Is_Full (S : Stack) return Boolean is abstract;
procedure Push (S : in out Stack; I : in Item) is abstract with Pre'Class => not Is_Full (S), Post'Class => not Is_Empty (S); private …
end Stack_Interfaces;
Pre- and Postconditions (2)• Unified syntax for aspect specifications
• Semantic analysis of conditions is done at end of current list of declarations or at freeze point of subprogram
• Conditions can be verified dynamically like assertions, or statically by analysis tools and/or clever compilers
• Can specify classwide conditions and type-specific conditions. Classwide conditions are inherited by the corresponding primitive of each descendant type.
• Dynamic condition checking is controlled by assertion mode
• Check can be in caller or in callee.
Aspect Specifications• General mechanism to replace most attribute definition clauses and
assorted pragmas.
type Bit_Vector is array (natural range <>) of Boolean with pack;
function Square (x : Integer) return Integer with inline => True;
Overlay : Some_Type with address => Some_Object’address, atomic => False;
Pre- and postconditions (3)• New Attributes, for use in postconditions (illegal in any other context)
• X’Old denotes the value of X before subprogram starts execution (X can be an arbitrary expression)
procedure Incr (X : in out Integer) with post => (X = X’Old + 1);
• F’Result denotes the result of the current function call.
function Sin (X : Float) return Float with post => (Sin’Result <= 1.0);
Type invariantspackage Q is type T(...) is private with Type_Invariant => Is_Valid (T); function Is_Valid (X : T) return Boolean; -- analyzed later
type T2(...) is abstract tagged private with Type_Invariant'Class => Is_Valid (T2); function Is_Valid (X2 : T2) return Boolean is abstract;private …end Q;
Type Invariants (2)• For private types and type extensions.
• Classwide invariants and type-specific invariants• Inheritance follows Liskov’s rules
• Invariants are checked:– On object initialization– On conversion to the type– On return from function that creates object of the type– On return from subprogram that has (in)- out parameter of the type
• Not bullet-proof:– Still possible to modify object through access values– If invariant for private extension depends on visible inherited component,
invariant is at risk.
Invariants and inheritance• Aspect Type_Invariant for T is type-specific• Aspect Type_Invariant’class for T applies to all descendants of T
type Root is private with Type_Invariant’class => Root_OK (Root); -- boolean function
type Child is new Root and private with Type_Invariant’class => Child_OK (Child);
type Grandchild is new Child and private with Type_Invariant => Details_OK (Grandchild);
• Upon creation of an object of type Grandchild, Root_OK, Child_OK and Details_OK are checked.
Subtype Predicates• Applies to all subtypes:
type Rec is record A : Natural; end record; subtype Decimal_Rec is Rec with Dynamic_Predicate => Decimal_Rec.A mod 10 = 0;
• A predicate can be specified for any subtype• A predicate is not a constraint (akin to a null exclusion)• Most common use: non-contiguous enumeration types.• Two varieties: Static and Dynamic (GNAT conflates them)
Static predicates• Predicate composed of predefined comparison operators, literals, scalar
ranges, and membership tests : can be evaluated statically on scalar operands.
subtype T3 is Positive with Static_Predicate => T3 in 1 .. 10 or else T3 in 50 .. 60 or else T3 = 100; -- could be a single Ada 2012 membership test.
If a static predicate evaluates statically to False it is an error (as for a static expression that raises Constraint_Error)
No_Way : constant T3 := 70; -- illegal
Dynamic predicates• Predicate is an arbitrary expression:
subtype Prime is positive with Dynamic_Predicate => Clever_Primality (Prime);
• Cannot apply ‘first, ‘last, ‘range to subtype with predicate
• ‘pred and ‘succ give value of base type (as usual)
• Cannot use subtype with predicate as index_type, as choice in named_array_aggregate, or as loop parameter specification (anything that would imply some sequential processing to find next value)
Major topics• Program correctness
• Containers
• Constructs for expressiveness
• Visibility mechanisms
• Concurrency and real-times
• Anonymous access types and storage management
• Syntactic sweeteners
Containers• The Ada2005 library is sparse, compared with those of other
languages, and with the state of the art in data-structure design.
• RM A.18.19 - A.18-25 Bounded containers• RM A.18.18 Holder container• RM A.18.17 Multiway tree container• RM A.18.27 – A 18.31 Queue containers
• Throughout : Accessors and Iterators for Containers
Bounded containers• Existing containers use dynamic memory allocation: not
convenient in high-integrity applications
• Introduce stack-allocated containers with defined maximum capacity:
• type Vector (Capacity : Count_Type) is tagged private;
Holder container• Cannot create an object of an indefinite type that can hold any value of the
type:• X : T’class; -- illegal without initialization• (can use access type and indefinite designated type).
• Better to define container that can hold single indefinite item:
generic type Element_Type (<>) is private; with function "=" (Left, Right : Element_Type) return Boolean is <>; package Ada.Containers.Indefinite_Holders is type Holder is tagged private; pragma Preelaborable_Initialization (Holder); Empty_Holder : constant Holder; …
Multiway trees• What, no trees in the library?
• Multiway trees are threaded every which way:• Node has sequence of descendants, traversal functions include
– Parent, First_Child, Last_Child– Next_Sibling, Previous_Sibling
• Can search and iterate over whole tree, over subtree, over children
• Can insert and delete elements, children, subtrees
• Indefinite and bounded versions also available
Queue containers• Considered too trivial to bother with in Ada 2005• Less trivial if must be task-safe• Provide common interface:
generic type Element_Type is private; package Ada.Containers.Synchronized_Queue_Interfaces is type Queue is synchronized interface; -- isn’t Ada2005 great? procedure Enqueue (Container : in out Queue; New_Item : in Element_Type) is abstract with Synchronization => By_Entry; procedure Dequeue ….…• Implement interface in bounded queues, unbounded queues, and priority
queues.
Major topics• Program correctness
• Containers
• Constructs for expressiveness
• Visibility mechanisms
• Concurrency and real-time
• Anonymous access types and storage management
• Syntactic sweeteners
Programming expressiveness• More powerful functions• Better iterators on all containers
• RM 5.5.2 (AI05-0139) Iterators• AI05-0142 Explicitly aliased parameters• AI05-0143 In Out parameters for functions• AI05-0144 Detecting dangerous order dependences• AI05-0177 expression functions
Iterator machinery• Generalized reference• Generalized indexing• Change to freezing rules for incomplete types
• All of this is invisible to the user who just wants to iterate over containers:
• for Item of My_Bag loop Mangle (Item); end loop;
Generalized reference• Can define aspect on type with an access discriminant:
type Wrapper (Data : access Integer) is null record with Implicit_Dereference => Data; function Find (From : aliased in out Box; Key : String) return Wrapper;
find (My_Box, “green”) := 15; -- equivalent to find (My_Box, “green”).Data.all
Generalized indexing• Another aspect that generalizes the indexed component notation of arrays.
– Array => Container– Index => Cursor
• We want My_Bag (That_One) to be analogous to Arr (N) type Bunch is tagged null record with Variable_Indexing => Reference;
function Reference (Obj : Bunch; S : String) return Wrapper; -- returns a reference type My_Bag (“Nines”) := 999;
-- equivalent to Reference (My_Bag, “nines”).data.all := 999;
Putting it together: iterators• An iterator wraps a pointer to a container, and has iteration operations (first,
next, last):
generic type Cursor; -- formal incomplete type with function Has_Element (Position : Cursor) return Boolean;package Ada.Iterator_Interfaces is pragma Pure; type Forward_Iterator is limited interface;
function First (Object : Forward_Iterator) return Cursor is abstract;
function Next (Object : Forward_Iterator; Position : Cursor) return Cursor is abstract; … Instantiation has to provide concrete cursor
Uniform structure for predefined containers: with Ada.Iterator_Interfaces; … generic type Element_Type is private; … package Ada.Containers.Doubly_Linked_Lists is … type List is tagged private with Constant_Indexing => Constant_Reference, Variable_Indexing => Reference, Default_Iterator => Iterate, Iterator_Element => Element_Type;
type Reference_Type (Element : not null access Element_Type) is private with Implicit_Dereference => Element; … function Reference (Container : aliased in out List; Position : Cursor) return Reference_Type;
function Iterate (Container : List) return List_Iterator_Interfaces.Reversible_Iterator'Class;
At the end: simple syntax for generalized loops for Cursor in Iterate (Container) loop Container (Cursor) := Container (Cursor) + 1; end loop;
-- container (cursor) means -- reference (container, cursor).Element.all
for Thing of Box loop Modify (thing); end loop; -- cursor is implicit
Both forms apply to arrays and containers. (no iteration over holder containers or queues)
In-out parameter for functions and their price:Detecting dangerous order dependences
• In-out parameters for functions and unspecified order of evaluation are a bad combination!
• F (Obj) + G (Obj)• Is problematic if F and/or G have side-effects on their actuals
• New rule provides a precise statically checkable definition of identity and overlap between objects. Compiler can then verify that:
• in a complex expression involving a function call with a modifiable parameter, there is no other component of the expression that denotes the same object or a portion of it.
Programming expressiveness (2)• Flexible syntactic forms for predicates in contracts and elsewhere
• AI05-0147 Conditional expressions• AI05-0158 Generalizing membership tests• AI05-0176 Quantified expressions• AI05-0177 expression functions• AI05-0188 Case expressions• AI05-0191 Aliasing predicates
Conditional Expressions
Value:= (if X > Y then F (X) else G (Y));
• If result type is Boolean, else_part can be omitted.
• Generally parenthesized
• Must work with classwide types and anonymous access types (some complication when branches have different types)
Extending membership operations• The argument of a membership test can be a set of values:
if (C not in 'A' | 'B' | 'O’) then Put_Line ("invalid blood type"); raise ER_Error; else Perform_Transfusion (500 * cc); end if;
Expression functions
• To simplify the writing of pre/postconditions and predicates, allow expression functions (aka function bodies in package specs):
• function Cube (X : integer) return Integer is (X ** 3) ;• Can be used as completions• Not quite a new idea (FORTRAN had function statements half-a-
century ago)
Quantified expressions Predicate states that A is sorted in increasing order:
(for all J in A'First .. T'Pred(A'Last) => A (J) <= A (T'Succ (J)))
Predicate asserts that N is composite:
(for some X in 2 .. N / 2 => N mod X /= 0)
Computation is short-circuited.some is a new reserved word
Non-intuitive boundary case:
• (for all X in empty_set => P (X)) is always True
• (for some X in empty_set => P (X)) is always False
• Common convention in set theory, arbitrary but settled• Want to preserve identity:
for all X in S => P (x) = not (for some X in S => not P (X))
Putting it together:• Specifying the behavior of a linear search function:
function Test_Recovery_Highest (S : Set) return Integer with post => (for all Cu in S => Test_Recovery_Highest'Result >= Element (Cu));
Major topics• Program correctness
• Containers
• Constructs for expressiveness
• Visibility mechanisms
• Concurrency and real-time
• Anonymous access types and storage management
• Syntactic sweeteners
Visibility mechanisms• Need more flexible ways to name entities in the complex
environment in which a unit is compiled.
• Incomplete types can be useful in additional contexts
• RM 8.4 (AI05-0150) Use all type clause• RM 3.10.1 (AI05-0151) Allow incomplete types as parameter and
result types• RM 3.10.1 (AI05-0162) Allow incomplete types to be completed by
partial views
More uses for use (and more uses for all) package P is type T is new Integer; function Nth (X : T; Expon : Natural) return T; end P; package body P is … end P;
X : T; -- illegal without use package clause
Y : P.T := X * 25; -- illegal without use type clause
Z : P.T := Nth (X, 5); -- illegal without use all type clause
Major topics• Program correctness
• Containers
• Constructs for expressiveness
• Visibility mechanisms
• Concurrency and real-time
• Anonymous access types and storage management
• Syntactic sweeteners
Concurrency and real-time features• Need to address the multicore revolution• Better scheduling tools justify more elaborate constructs• Mostly real-time annex and shared variable control• Mostly suggestions from IRTAW
• RM D.16 (AI05-0167) Managing affinities on multiprocessors• C.6 (AI05-0117) Memory barriers and Volatile objects• D.14.2 (AI05-0169) Defining group budgets for multiprocessors• D.13 (AI05-0171) Ravenscar Profile for Multiprocessor Systems• RM D.2.4 (AI05-0166) non-preemptive dispatching (Yield operations)• RM D.10 (AI05-0168) Extended suspension objects• RM D.14.3 (AI05-0170) Monitoring the time spent in Interrupt Handlers• RM D.10.1 (AI05-0174) Task barriers
Managing affinities• Construct to map tasks to processing units (core/chip)
package System.Multiprocessors is type CPU_Range is range …… package System.Multiprocessors.Dispatching_Domains is type Dispatching_Domain (<>) is limited private; function Create (First, Last: CPU) return Dispatching_Domain;
procedure Set_CPU (CPU : in CPU_Range; T : in Task_Id := Current_Task);
function Get_CPU (T : in Task_Id := Current_Task) return CPU_Range; …
Implementation must describe how ranges map to actual silicon (hot topic)
Synchronous barriers• More flexible than using a protected type, and usually supported
by OS
package Ada.Synchronous_Barriers is subtype Barrier_Limit is Positive range 1 .. Implementation_defined-
type Synchronous_Barrier (Release_Threshold : Barrier_Limit) is limited private;
procedure Wait_For_Release (The_Barrier : in out Synchronous_Barrier; Notified : Boolean);
Major topics• Program correctness
• Containers
• Constructs for expressiveness
• Visibility mechanisms
• Concurrency and real-time
• Anonymous access types and storage management
• Syntactic sweeteners
Anonymous access types and storage management• Need to simplify accessibility rules for anonymous types• Need more flexible storage reclamation mechanisms
• AI05-0148 Accessibility of anonymous access stand-alone objects• AI05-0149 Access types conversion and membership
• The heart of darkness (RM 3.10.2) !
• AI05-0152 Restriction No_Anonymous_Allocators• AI05-0189 Restriction No_Allocators_After_Elaboration• AI05-0190 Global storage pool controls• AI05-0193 Alignment of allocators
Major topics• Program correctness
• Containers
• Constructs for expressiveness
• Visibility mechanisms
• Concurrency and real-time
• Syntactic sweeteners
Syntactic sweeteners• What, no “continue” statement?• Where are pragmas legal?
• RM 2.8 (AI05-0100) Placement of pragmas• RM 2.8 (AI05-0163) Pragmas instead of null• RM 5.1(120 (AI05-0179) Labels at end of a
sequence_of_statements
The language design imperative
• “You boil it in sawdust: you salt it in glue: You condense it with locusts and tape:Still keeping one principal object in view— To preserve its symmetrical shape.”
The Hunting of the snark
Discards• AI05-0074-2 Allowing an explicit "end private;" in a package spec
• AI05-0074-3 Deferred instance freezing
• AI05-0135 Integrated nested packages
• AI05-0140-1 Identity functions
• AI05-0175-1 Cyclic fixed point types
• AI05-0187-1 Shorthand for assignments with expressions naming target ( a += 1)• (but stay tuned for Ada 2020)
• Check definition of “the software present tense”• Active testbed for proposed language extensions
GNAT does it all!