Fact-checked by Grok 2 weeks ago

Abstract data type

An abstract data type (ADT) is a for a in , defined solely by its behavioral properties—including the set of possible values and the operations that can be performed on them—without specifying any particular implementation or internal representation. This abstraction allows programmers to reason about the data type's functionality in terms of inputs, outputs, and effects, promoting modularity and reusability in . The concept of ADTs was formally introduced in 1974 by and Stephen Zilles in their seminal paper, which emphasized programming languages that support the definition and use of such types to manage complexity in large systems. Unlike concrete data structures, which provide specific ways to store and manipulate data (e.g., arrays or linked lists), ADTs focus on the interface, encapsulating implementation details to hide them from users and prevent direct access to the underlying representation. This principle of , as articulated in related practices, enhances maintainability by allowing changes to the implementation without affecting dependent code. Key components of an ADT include constructors (to create instances), accessors (to retrieve information), mutators (to modify the data), and iterators (to traverse elements), all specified independently of how they are realized. For instance, a ADT might define operations like push (add an element), pop (remove the top element), and isEmpty (check if empty), which could be implemented using an array or a without altering the user's view. Similarly, , , and set ADTs provide standardized behaviors for first-in-first-out ordering, sequential access, and unique element storage, respectively. In practice, ADTs form the foundation for higher-level abstractions in programming languages, often implemented via interfaces in object-oriented paradigms (e.g., Java's List interface) or modules in procedural languages, enabling efficient algorithm design and data structure selection based on performance needs like time and space complexity. By decoupling specification from implementation, ADTs support software evolution, testing, and verification, making them essential for scalable and reliable systems.

Fundamentals

Definition

An abstract data type (ADT) is a for a that specifies its behavior solely through a set of operations and their semantics as observed by the user, independent of any underlying implementation details. Formally, an ADT consists of a —a finite or of possible values—and a collection of operations defined over this , including constructors that create new values, queries that inspect existing values without altering them, and modifiers that change the state of values. The semantics of these operations are captured from the user's viewpoint via preconditions (requirements that must hold before an operation is invoked) and postconditions (guarantees about the resulting state after invocation), ensuring predictable behavior without exposing internal representations. This approach distinguishes the abstract view of an ADT, which emphasizes behavioral specification and user-facing interfaces, from the concrete view, which deals with specific implementation choices such as data structures and algorithms. In the abstract view, the focus is on what the type does—its observable effects—rather than how it is realized internally, allowing multiple implementations to satisfy the same specification. For instance, operations are categorized as creators (e.g., initializing an empty instance), producers (e.g., combining existing values to form new ones), observers (queries returning information), and mutators (modifiers updating values), each rigorously defined to maintain consistency across uses. The core motivation for ADTs lies in encapsulating implementation details to enhance modularity and reusability in software design, enabling developers to build and maintain complex systems by treating types as black boxes whose internals can evolve without breaking dependent code. This abstraction facilitates clearer program organization, reduces coupling between components, and supports verification by focusing on behavioral correctness. The concept of ADTs was first formally introduced by Barbara Liskov and Stephen Zilles in 1974 as a means to address challenges in programming with high-level languages.

Operational Semantics

Operational semantics for abstract data types (ADTs) provides a formal method to specify the behavior of an ADT by defining transition rules that describe how operations transform the abstract from a pre-state to a post-state. This approach models the execution of operations as a of transitions, often using term rewriting systems or reduction rules to ensure deterministic and well-defined outcomes, such as through properties like Church-Rosser that guarantee unique normal forms for valid computations. The signature of an ADT in this semantic framework consists of a collection of operation symbols, each with specified input and output types, along with visibility distinctions such as public operations accessible to users and private ones internal to the ADT's specification. These signatures delineate the interface of the ADT, ensuring that operations adhere to typed domains without exposing implementation details. For instance, the signature might include types for values like integers or booleans, with operations mapped to appropriate arity and result types. Operations within the signature are typically categorized into four types: creators, which initialize new instances of the ADT (e.g., an empty ); producers, which generate new values from existing ones without modifying the state (e.g., for lists creating a new list from an element and an existing list); observers, which query the state without alteration (e.g., retrieving the top element); and mutators, which modify the underlying state (e.g., adding or removing elements). This classification aids in reasoning about the ADT's behavior by clarifying the role each operation plays in . To ensure correctness, operations are further constrained by preconditions, which specify the requirements that must hold for the operation to be valid (e.g., a stack must not be empty before popping), and postconditions, which guarantee the outcomes upon successful execution (e.g., the state reflects the modification and returns the expected value). These contracts enable of ADT usage, preventing errors like in invalid states. The abstract state in is treated as a mathematical , such as a in an , independent of any concrete physical or machine representation, allowing focus on behavioral across implementations. This abstraction facilitates proofs of properties like observational , where two ADTs are indistinguishable if their observable behaviors match under the same operations.

Historical Context

Origins

The concept of abstract data types (ADTs) emerged from early efforts in programming language design to support and in the late 1960s. 67, developed in 1967 at the Norwegian Computing Center, introduced the class construct, which allowed for the definition of modular units combining data and procedures, facilitating by enabling the creation of reusable, self-contained components for tasks. Similarly, , finalized in 1968, provided mechanisms for user-defined modes (types) and strong typing, allowing programmers to abstract data structures and operations orthogonally, which supported the definition of complex, user-specific data abstractions beyond built-in primitives. These innovations laid groundwork for separating data representation from usage, promoting without full object-oriented paradigms. Influences from in the late further shaped these ideas, drawing on formal systems like typed calculi to emphasize safe, composable data representations and operations. Modular principles, inspired by mathematical type systems, encouraged viewing programs as hierarchies of abstract entities, where details could be isolated to enhance reliability and reusability in large systems. The initial formalization of ADTs occurred through the work of and Stephen Zilles at between 1972 and 1974, motivated by the design of the CLU programming language. Their 1974 paper articulated ADTs as extensible built-in abstractions, defined by behavioral specifications (axioms for operations) independent of concrete implementations, enabling programmers to augment language primitives with custom types like stacks or tables. This approach connected directly to in , a predating full , by isolating data behavior from representation to manage complexity in reliable system design, as echoed in contemporary modularization efforts. Early adoption faced significant challenges due to the lack of native language support for hiding implementations, forcing programmers to rely on conventions or external tools, which undermined the benefits of abstraction and led to brittle, non-portable code. Liskov and Zilles highlighted this gap, arguing that without built-in mechanisms for specification and enforcement, achieving true data independence remained difficult in existing languages like ALGOL or PL/I.

Key Milestones

In 1974, and Stephen Zilles published a seminal paper formally introducing abstract data types (ADTs) as a programming to augment built-in abstractions with user-defined ones, emphasizing their role in modular program design. During the late and , ADTs were implemented in several programming languages to support and ; for instance, CLU, developed by Liskov and her team starting in 1975, provided mechanisms for defining ADTs with type-parameterized abstractions. Similarly, the language, finalized in 1977, incorporated modules for encapsulating data and operations, promoting verifiable system programs through . Ada's 1983 standardization introduced packages as a core feature for specifying ADTs, enabling separate compilation and abstraction in large-scale systems. In the 1980s, ADTs influenced (OOP) languages, where Smalltalk-80 treated classes as implementations of ADTs to enforce and reusability through restricted access to internal representations. Concurrently, advanced with the (VDM), which from the early 1980s used mathematically based ADTs for rigorous specification and verification of software systems. The 1990s saw broader industry adoption through standardization; Java's interfaces, introduced in its 1995 design and 1996 release, formalized ADTs by defining behavioral contracts without details, facilitating polymorphism in enterprise applications. Likewise, C++'s abstract classes, refined in the language's evolution through the and standardized in 1998, allowed pure virtual functions to specify ADT interfaces, distinguishing them from concrete implementations in . Early ADT support often lacked robust generics, limiting reusability across types until later developments like Ada's generics in 1983 and C++ templates in the 1998 standard, though full parameterization in mainstream languages such as awaited 2004.

Examples

Basic Examples

One of the simplest abstract data types is the abstract , which models a mutable holding a single value from a predefined D. It provides two core operations: get(V), which returns the current value stored in variable V, and set(V, x), which updates V to hold the value x \in D, returning the modified variable. The behavioral semantics are specified by the axiom \text{get}(\text{set}(V, x)) = x, ensuring that retrieval immediately after an update yields the newly set value, while the maintains that V always contains a valid element from D. This ADT demonstrates encapsulation by hiding the internal representation and focusing solely on observable behavior through these operations. The abstract stack exemplifies a linear ADT enforcing last-in, first-out (LIFO) ordering, where elements are added and removed exclusively from the "top." Key operations include creating an empty stack, push(S, x) which places x onto stack S and returns the updated stack S', pop(S) which removes and returns the top along with the resulting stack (x, S') provided S is non-empty (a ), and is_empty(S) which indicates whether S contains no elements. These can be specified with pseudo-signatures such as:
push: Stack × Element → Stack
pop: Stack → (Element × Stack)
is_empty: Stack → Boolean
The semantics preserve LIFO behavior via axioms like \text{pop}(\text{push}(S, x)) = (x, S) and \text{is_empty}(\text{create\_empty}()) = \true, with the invariant that each push increases the stack size by one and each pop decreases it by one, ensuring predictable state transitions without exposing internal structure. Complementing the stack, the abstract queue is a linear ADT that maintains first-in, first-out (FIFO) ordering, adding elements at the "rear" and removing them from the "front." Its operations consist of creating an empty queue, enqueue(Q, x) which appends x to the rear of queue Q and returns the updated Q', dequeue(Q) which removes and returns the front element along with the resulting queue (y, Q') if Q is non-empty (precondition), and is_empty(Q) to check emptiness. Pseudo-signatures include:
enqueue: Queue × Element → Queue
dequeue: Queue → (Element × Queue)
is_empty: Queue → Boolean
Behavioral semantics are defined by axioms such as the front of \text{enqueue}(Q, x) being the same as the front of Q (if non-empty) and the rear accumulating in insertion order, upholding the invariant that dequeues retrieve elements in the exact sequence of enqueues, thus guaranteeing discipline independent of representation. These basic examples build on the operational semantics of ADTs by specifying behaviors through operations and invariants that abstract away details.

Common ADTs

Common abstract data types (ADTs) extend basic structures like stacks and queues by providing more versatile mechanisms for managing collections of data in programming applications. These ADTs emphasize specific behaviors and invariants, such as ordering, uniqueness, or associations, without specifying underlying representations. Among the most frequently used are lists, priority queues, sets, and maps (also known as dictionaries), each supporting a core set of operations tailored to their purpose. The ADT represents an ordered of elements, allowing dynamic insertion and removal while preserving relative order. Key operations include:
  • cons: Prepends a new element to the front of the list, returning a new list with the element as the head and the original list as the .
  • head: Retrieves the first element of a non-empty list.
  • tail: Returns the list without its first element.
  • length: Returns the number of elements in the list.
Lists find applications in symbolic processing, where they model expressions as nested structures for manipulation in languages like . The ADT maintains a collection of elements ordered by priority, typically extracting the highest-priority (e.g., minimum or maximum) element first. Core operations include:
  • insert: Adds a new element with its associated priority.
  • extract-min: Removes and returns the element with the lowest priority.
  • decrease-key: Reduces the priority of an existing element, useful for updating costs in dynamic scenarios.
This ADT enforces heap-like semantics, where elements are organized to efficiently support priority-based access without maintaining full sorted order. Priority queues are essential in scheduling algorithms, such as Dijkstra's shortest algorithm, which uses them to select the next node with the minimum tentative distance in . The set ADT models an unordered collection of unique , enforcing an that no duplicates are allowed. operations are:
  • insert: Adds an if it is not already present.
  • delete: Removes a specified if it exists.
  • member: Checks whether an is in the set (often called find or contains).
  • : Combines two sets, including all unique from both.
Sets support mathematical set operations while abstracting away ordering details. The (or ) ADT stores associations between unique s and corresponding values, enabling efficient retrieval based on keys. Primary operations include:
  • insert: Associates a key with a value, overwriting if the key already exists.
  • lookup: Retrieves the value associated with a given key (or indicates absence).
  • delete: Removes the key-value pair for a specified key.
This ADT ensures no duplicate keys, providing a foundation for associative storage. In modern database systems, sets and maps underpin relational models, where tables act as sets of tuples and keys map attributes to values for querying and enforcement. These ADTs are often parameterized to work with generic element types, enhancing reusability across applications.

Implementation

General Approaches

One fundamental principle in implementing abstract data types (ADTs) is representation independence, which ensures that the choice of internal data structures—such as or —does not affect the external or client , allowing implementations to evolve without breaking dependents. This property is achieved by hiding the representation details behind an opaque type, enabling multiple equivalent implementations that preserve behavioral equivalence under state-dependent relations. For instance, a ADT can use a circular for efficient access or a for dynamic sizing, with the interface remaining unchanged to maintain abstraction. Implementations of ADTs vary across programming paradigms, particularly between imperative and functional approaches. In imperative languages, ADTs often rely on mutable state managed via pointers or references, allowing in-place modifications for efficiency but introducing risks of and side effects. Conversely, functional implementations emphasize immutability, using techniques like or persistent data structures to simulate operations without altering state, which enhances and at the cost of potential space overhead from copying. These differences highlight a in versus , with imperative styles suiting resource-constrained environments and functional ones favoring . Programming languages provide specific mechanisms to enforce ADT abstractions. In object-oriented paradigms, abstract classes and interfaces define the ADT's operations without exposing implementations, promoting polymorphism and loose coupling. Modules in languages like Modula-2 or Ada encapsulate ADTs by controlling visibility, while generics or parametric polymorphism—supported in C++, Java, and Haskell—enable reusable implementations parameterized by types, avoiding code duplication for variant forms like integer or string stacks. These features collectively support information hiding and extensibility without compromising the ADT's semantic boundaries. Error handling in ADT implementations addresses precondition violations, such as attempting to pop from an empty . One approach uses exceptions to signal errors, propagating them up the call stack for centralized recovery, which separates normal flow from error cases but incurs runtime overhead. Alternatively, returning error values—such as optional types or result monads—integrates errors into the , enabling explicit checks without unwinding, though this requires disciplined client-side handling to avoid ignoring failures. The choice depends on context: exceptions suit rare, recoverable errors in imperative settings, while functional languages favor value-based returns for composable error propagation. A key trade-off in ADT design balances extensibility via against through encapsulation. allows subclassing to extend ADTs with new behaviors, facilitating reuse but potentially violating encapsulation by exposing internal details to subclasses, leading to issues. Encapsulation, by contrast, strictly hides representations to prevent unintended dependencies, enhancing maintainability but limiting extensibility without recomposition. In procedural data abstraction (a form of ), this tension arises as eases adding operations but complicates representation changes, whereas pure ADTs prioritize hiding for optimization and independence. Modern verification tools like Dafny address ADT correctness by automatically checking functional properties, such as representation independence and operation invariants, through deductive verification integrated with the language. Dafny's support for ghost code and lemmas enables proofs of ADT behaviors in imperative programs with pointers, bridging implementation and specification without manual theorem proving. This approach ensures implementations adhere to abstract semantics, reducing errors in complex systems.

Case Study: Stack

The stack abstract data type (ADT) provides a concrete example of ADT realization through distinct implementation paradigms, highlighting trade-offs in efficiency, mutability, and persistence. In the imperative style, stacks are commonly implemented using a dynamic array to support efficient access and mutation, allowing for amortized constant-time operations on push and pop. This approach relies on in-place modifications, with resizing mechanisms to handle growth dynamically. A typical imperative implementation initializes an array with a fixed initial capacity, tracking the current size separately. The push operation adds an element to the end of the array and increments the size; if the array is full, it allocates a new array (often doubling the capacity), copies existing elements, and then inserts the new one. Pseudocode for these core operations is as follows:
class Stack {
    int[] data;
    int size;
    int capacity;

    initialize() {
        capacity = 10;  // Initial capacity
        data = new int[capacity];
        size = 0;
    }

    push(int x) {
        if (size == capacity) {
            capacity *= 2;
            int[] newData = new int[capacity];
            for (int i = 0; i < size; i++) {
                newData[i] = data[i];
            }
            data = newData;
        }
        data[size] = x;
        size++;
    }

    pop() {
        if (size == 0) {
            throw new Error("Stack underflow: cannot pop from empty stack");
        }
        size--;
        return data[size];
    }
}
This maintains the invariant that the array elements from index 0 to size-1 represent the stack (bottom to top), with pop enforcing the precondition of non-emptiness by raising an exception on violation to prevent invalid states. In contrast, a functional implementation uses immutable (paired structures of head and tail), where each operation returns a new list without altering the original, enabling persistence for concurrent or historical access. Push prepends an element to form a new list via , while pop destructures the list to extract the head and return the tail. Pseudocode in a functional style (inspired by list-based modules) appears as:
type Stack a = List a

empty: Stack a = Nil

push: a -> Stack a -> Stack a
push x s = Cons(x, s)

pop: Stack a -> (a, Stack a)
pop Nil = error "Stack underflow: cannot pop from empty stack"
pop (Cons(x, s)) = (x, s)

isEmpty: Stack a -> Bool
isEmpty Nil = True
isEmpty (Cons(_, _)) = False
Here, cons ensures the top element is always accessible in O(1) time, and destructuring upholds the non-empty for pop by signaling an otherwise, preserving and avoiding side effects. Comparing the two, the imperative dynamic array achieves amortized O(1) time for both and pop through resizing (where occasional copies are offset by many O(1) operations), using space overall with mutation for efficiency. The functional cons-list approach also yields O(1) time per operation via structural sharing (no full copies needed), but each creates a new node, leading to space per version for persistence, which supports multiple views without interference at the cost of higher memory usage for long sequences. Both paradigms enforce key invariants like stack ordering and bounded operations through checks, though functional styles naturally avoid issues via immutability.

Advanced Concepts

Aliasing and Side Effects

Aliasing in abstract data types (ADTs) refers to the situation where multiple references or pointers point to the same underlying abstract state, potentially leading to unexpected side effects when the state is mutated through one reference. This sharing of state violates the intended of an ADT's abstract view, as operations that should be independent can interfere with each other. A key issue arises when mutator operations, such as insertions or deletions, are performed via one alias, causing observer operations (like queries on size or contents) accessed through another alias to reflect unintended changes. For instance, if two in a both the same ADT instance, popping an element from one variable will unexpectedly alter the perceived top element when querying the other variable, breaking the abstraction's of predictable . Such alias-induced mutations, often termed "mutation at a distance," complicate reasoning about program correctness and can introduce subtle bugs in imperative languages supporting mutable references. The challenges of emerged prominently in the 1980s alongside the rise of (OOP), where encapsulation via objects amplified the risks of shared references in complex hierarchies. addressed related concerns in her 1987 work on data abstraction and hierarchy, introducing the substitution principle—now known as the (LSP)—which requires subtypes to preserve the observable behavior of supertypes, thereby mitigating aliasing effects in polymorphic contexts by ensuring no unexpected state changes propagate through substitutions. To formally specify ADTs in the presence of , postconditions must be extended with conditions that explicitly describe unaffected portions of the state and assert "no visible side effects" on non-aliased observers. These conditions, often integrated into logics, ensure that mutations are localized and do not leak through aliases, enabling modular proofs of ADT correctness despite shared references. Several solutions address in ADTs. models enforce unique references to , restricting to prevent mutable aliases and promoting single-ownership policies for safer encapsulation. techniques allow shared immutable views of the state, creating mutable copies only upon modification to balance efficiency and isolation. Immutable ADTs eliminate mutation entirely, ensuring that aliases always observe consistent, unchanging without side effects. In modern languages like , the borrow checker implements an model that dynamically tracks references, prohibiting mutable aliases (the "aliasing XOR mutability" rule) to guarantee at without runtime overhead.

Complexity Analysis

Complexity analysis for abstract data types (ADTs) focuses on specifying the time and space efficiency of operations in terms of abstract parameters, such as n representing the current size of the data collection, without depending on any particular concrete representation. This approach ensures that the bounds hold for any valid implementation of the ADT, emphasizing worst-case or average-case performance over sequences of operations. For instance, specifications often use asymptotic notation to declare that an operation runs in O(f(n)) time, providing a guarantee independent of implementation details like versus usage. Representative examples illustrate these abstract bounds. For the stack ADT, both push and pop operations achieve O(1) worst-case time complexity, as they involve accessing or modifying only the top element regardless of stack size. In contrast, the priority queue ADT requires O(\log n) time for insert and extract-min operations in the worst case, reflecting the need to maintain heap order across the structure. These bounds are derived from the inherent operations of the ADT, such as comparisons or rearrangements, and apply uniformly to balanced tree or heap-based realizations. Amortized analysis extends worst-case bounds to sequences of operations on dynamic ADTs, such as stacks or queues that resize to accommodate growth. For a stack implemented with a that doubles in size upon overflow, individual inserts may take O(n) time during resizing, but the amortized cost per insert is O(1) over a sequence of m operations, as the total cost is bounded by O(m). This is typically proven using methods like the aggregate analysis, which sums costs over the , or the , which assigns credits to operations to cover occasional expensive resizes. Such analysis is crucial for ADTs supporting unbounded growth, ensuring predictable average performance. Space complexity for ADT operations is similarly specified abstractly, often focusing on auxiliary space beyond the data itself. Mutator operations like insert or update in many ADTs, such as or stacks, require O(1) auxiliary space when performed in-place, meaning no additional proportional is needed outside the existing . This bound holds independently of the , as long as the implementation avoids unnecessary copies, and contrasts with operations like that may demand O(n) temporary space. A key tool in ADT specifications is Big-O notation, which formalizes upper bounds on growth rates, often analyzed relative to abstract computational models like the (RAM) to ensure practicality. Additionally, information-theoretic lower bounds establish fundamental limits; for example, any comparison-based ADT operation requires \Omega(n \log n) time in the worst case, as it must distinguish among n! possible permutations, each comparison providing at most 1 bit of . This bound, derived from the , applies to any ADT realization relying on comparisons.

Parameterized and Restricted Types

Parameterized abstract data types (ADTs) incorporate type parameters to define structures and operations that are polymorphic over arbitrary types, enabling a single specification to apply to multiple element types without duplication. This parameterization, a key aspect of , allows developers to create reusable components where the type of elements is specified at time rather than hardcoded. For example, a stack ADT can be parameterized as Stack, with operations like (T element) and T pop() defined generically over the type variable T, ensuring the ADT behaves correctly for any substitutable type. In practice, languages such as C++ use templates to implement parameterized ADTs, as seen in the (STL), where containers like std::vector and std::list are instantiated for specific types at , supporting efficient, . Similarly, Java's generics, introduced in JDK 5.0 in 2004, provide parameterized types like ArrayList, with erasure-based implementation that enforces type safety during compilation while maintaining binary compatibility. These mechanisms extend ADT specifications by including type variables in signatures, often with polymorphic operations that do not depend on the concrete type of T. Restricted types, or bounded parameterization, further refine this by imposing constraints on type parameters to guarantee the availability of necessary operations, enhancing safety and expressiveness. For instance, a ADT might require T extends Comparable, ensuring elements support ordering via a compareTo , thus preventing with incomparable types like void or arrays. This bounding can be upper (e.g., T <: SomeInterface) or lower, and in specifications, it manifests as extended preconditions or postconditions, such as requiring that for all x, y in the queue, x.compareTo(y) yields a consistent total order. Bounded stacks illustrate a related restriction, where the ADT limits capacity to a fixed size N (e.g., via a constructor Stack(int capacity)), rejecting operations that would exceed this bound to model bounded buffers or prevent unbounded growth. The primary benefits of parameterized and restricted ADTs include across diverse types—such as implementing one stack for integers, strings, or custom objects—and compile-time that catches misuse early, reducing errors. However, challenges arise in implementation, particularly with instantiation overhead: in C++ templates, each unique type combination generates distinct code, leading to larger binaries and longer compilation times, though optimizations like explicit mitigate this in performance-critical scenarios. In contrast, Java's type erasure avoids but shifts some checks to casts. Overall, these features have become foundational in modern type systems, balancing generality with constraints for robust ADT design.

References

  1. [1]
    1.2. Abstract Data Types — CS3 Data Structures & Algorithms
    An abstract data type (ADT) is the specification of a data type within some language, independent of an implementation.
  2. [2]
    AbstractDataTypes - Computer Science
    Abstract data types are data types whose implementation is not visible to their user; from the outside, all the user knows about an ADT is what operations can ...
  3. [3]
    Programming with abstract data types - ACM Digital Library
    This paper presents an approach which allows ... However, in most of these languages, implementations of abstract data types are not first-class values.Missing: original | Show results with:original
  4. [4]
    Reading 10: Abstract Data Types - MIT
    The essential idea here is that an abstract data type is defined by its operations. The set of operations ... set of values, like the days of the week. We ...
  5. [5]
  6. [6]
    The class concept in the Simula programming language
    These are well suited for structured programming and for the production of secure, modular programs. ... SIMULA 67 is a general purpose programming language with ...Missing: 1967 | Show results with:1967
  7. [7]
    [PDF] Algol 68 - Software Preservation Group
    "abstraction" (1.1.4.2.b) of one of its alternatives.} c). An "alternative" is a nonempty sequence of "members" separated by commas. d). A "member" is either.
  8. [8]
    [PDF] On Understanding Types, Data Abstraction, and Polymorphism
    The above historical framework provides a basis for a deeper discussion of the relations among types, data abstraction, and polymorphism in real programming.
  9. [9]
    Programming with abstract data types | ACM SIGPLAN Notices
    Programming with abstract data types. Proceedings of the ACM SIGPLAN symposium on Very high level languages · Polymorphic type inference and abstract data types.Missing: original | Show results with:original
  10. [10]
    [PDF] A History of CLU - CSAIL Publications - MIT
    Dec 6, 1973 · Steve Zilles described his early work on specifying abstract data types; he gave the axioms for the soon to be notorious stack example. Carl ...
  11. [11]
    [PDF] Report on the Programming Language Euclid - Bitsavers.org
    This report describes a new programming language called Euclid, intended for the expression of system programs which are to be verified.Missing: hiding ADTs
  12. [12]
    [PDF] reference manual for the ADA programming language
    This is a reference manual for the Ada programming language, designed as a common language for large-scale, real-time systems.Missing: ADTs | Show results with:ADTs
  13. [13]
    [PDF] Reusability in the Smalltalk-80 Programming System
    Smalltalk-80 strongly encourages use of abstraction in two ways: by restricting the ability to refer to the implementation of a data type to a set of procedures ...
  14. [14]
    Specification aspects of VDM - ScienceDirect.com
    One aspect of the method is the concept of mathematically based abstract data types which can be used for specifications.
  15. [15]
    Java interfaces in CS 1 textbooks - ACM Digital Library
    Java's interface construct allows for a clear distinction between subtype polymorphism based on a shared interface and code reuse based on class extension ...
  16. [16]
    [PDF] Object-Oriented Programming Versus Abstract Data Types
    Abstract data types were first formulated in their pure form in CLU [31, 30] ... The following year, in 1974, Zilles published an influential paper with Barbara ...
  17. [17]
    Generic programming - Wikipedia
    Generic programming was introduced to the mainstream with Ada in 1977. With templates in C++, generic programming became part of the repertoire of professional ...
  18. [18]
    [PDF] Program Design With Abstract Data Types - DTIC
    Abstract: This paper explores the use of abstract data types as a modularization and structuring technique in the design of programs. The concepts of type ...<|separator|>
  19. [19]
    Stacks and Queues - cs.wisc.edu
    The only item that can be taken out (or even seen) is the most recently added (or top) item; a Stack is a Last-In-First-Out (LIFO) abstract data type. Here are ...Missing: seminal papers
  20. [20]
  21. [21]
    [PDF] ADTs and vectors, towards linked lists
    ➤ A list is empty, or contains an element and a list. ➤ Access head/first and tail/rest of list, see CList for details. ○ As CDT (concrete data type).
  22. [22]
    [PDF] Recursive Functions of Symbolic Expressions and Their ...
    In the LISP programming system we put more in the association list of a symbol than is required by the mathematical system described in the previous sections.
  23. [23]
    Priority Queues - Algorithms, 4th Edition
    Apr 24, 2022 · Priority queues are characterized by the remove the maximum and insert operations. By convention, we will compare keys only with a less() method.
  24. [24]
    [PDF] dijkstra-routing-1959.pdf
    1. 19. Page 2. 270. E. W. DIJKSTRA: the data for at most a branches, viz. the branches in sets I and II and the branch under consideration ...
  25. [25]
    [PDF] 1 An Abstract Data Type for Sets
    Note that the bulk operations, intersection, union, difference can be implemented in terms of the operations find, insert, delete. Indeed, they are the bulk ...Missing: uniqueness | Show results with:uniqueness
  26. [26]
    Mapping Structures - Tools for Thinking About Programs: Data ...
    Let's turn our intuition of how a language dictionary works into a general abstract data type capturing the essence of a mapping data structure. The map ...
  27. [27]
    [PDF] A Relational Model of Data for Large Shared Data Banks
    The adoption of a relational model of data, as described above, permits the development of a universal data sub- language based on an applied predicate ...
  28. [28]
    Representation independence and data abstraction
    In languages with abstract data type declarations, representation independence should hold for user-defined types as well as built-in types. We study the ...
  29. [29]
    Abstract Data Type Development and Implementation: An Example
    The methodology preserves a high degree of representation independence throughout both the design and implementation of complex systems. The methodology is ...
  30. [30]
    [PDF] Imperative functional programming - Microsoft
    Imperative functional programming uses monads to perform I/O in a non-strict, functional language, combining smaller programs for I/O, and using higher-order ...Missing: scholarly | Show results with:scholarly
  31. [31]
    Imperative functional programming - ACM Digital Library
    We present a new model, based on monads, for performing input/output in a non-strict, purely functional language. It is composable, extensible, efficient.
  32. [32]
    [PDF] A Comparison of Functional and Imperative Programming ...
    Imperative programming uses sequential statements, while functional programming uses relationships between mathematical expressions based on dependencies.
  33. [33]
    Defining ADTs with Interfaces, Generics, Enums, and Functions - MIT
    Java's interface is a useful language mechanism for expressing an abstract data type. An interface in Java is a list of method signatures without method bodies.Missing: 1995 | Show results with:1995<|separator|>
  34. [34]
    [PDF] A Comparative Study of Language Support for Generic Programming
    To aid in this process, we present results of an in-depth study comparing six programming languages that support generics: Stan- dard ML [35], C++ [17], Haskell ...
  35. [35]
    Exceptions and Error Handling, C++ FAQ - Standard C++
    In C++, exceptions are used to signal errors that cannot be handled locally, such as the failure to acquire a resource in a constructor.Exceptions And Error... · Why Use Exceptions? · Exception Handling Seems To...
  36. [36]
    Error handling: Exception or Result? - Enterprise Craftsmanship
    Mar 13, 2017 · In this post, we'll look at some practical examples of error handling. We will see whether it is better to use exceptions or the Result class to deal with ...
  37. [37]
    error handling - Result object vs throwing exceptions
    Feb 12, 2020 · A return value is one of many possible outcomes of a computation. An error is an unexpected situation which needs to be reported to the caller.Why are exceptions considered better than explicit error testing?The modern way to perform error handling...More results from softwareengineering.stackexchange.com
  38. [38]
    [PDF] Encapsulation and Inheritance in Object-Oriented Programming ...
    One of its prime features is support for data Abstraction, the ability to define new types of objects whose behavior is defined Abstractly, without reference to.Missing: ADT trade- scholarly
  39. [39]
    Difference Between Information Hiding and Encapsulation | Baeldung
    Jan 16, 2024 · Information hiding is a programming principle that aims to prevent the direct modification of the data of a class. Also, it provides a strict ...
  40. [40]
    [PDF] Dafny: An Automatic Program Verifier for Functional Correctness
    This paper gives a tour of the language and verifier Dafny, which has been used to verify the functional correctness of a number of challenging pointer-based ...
  41. [41]
    Dafny Documentation
    The Dafny static program verifier can be used to verify the functional correctness of programs. This document is a reference manual for the programming language ...
  42. [42]
    [PDF] Using Dafny, an Automatic Program Verifier - Rustan Leino
    Dafny is an automated program verification system based on dynamic frames, designed for static verification and producing .NET executables.
  43. [43]
    Javanotes 9, Section 9.3 -- Stacks, Queues, and ADTs
    The term abstract data type, or ADT, refers to a set of possible values and a set of operations on those values, without any specification of how the values are ...
  44. [44]
    [PDF] Contracts for First-Class Classes - Northeastern University
    Thus, we specify that the stack must be non- empty when pop is called. 3.2.1 Contract Boundaries. In contrast to Eiffel, contracts in PLT Scheme are checked ...<|control11|><|separator|>
  45. [45]
    11.8.1. Example: Stacks · Functional Programming in OCaml
    Here are a few familiar operations on stacks along with their types. module type Stack = sig type 'a t val empty : 'a t val is_empty : 'a t -> bool val peek : ' ...
  46. [46]
    [PDF] Amorti ed Analysis (CLRS 17) CPS 230, Fall 2001 1 Amortized ...
    A stack can easily be implemented(using a linked list)such that Push and Pop each take (1)time per operation. •Consider the addition of another operation: - u ...
  47. [47]
    Aliasing in Object-Oriented Programming - ACM Digital Library
    Jan 1, 2013 · Aliasing occurs when two or more references to an object exist within the object graph of a running program. Although aliasing is essential ...<|separator|>
  48. [48]
    [PDF] Alias Types - Cornell: Computer Science
    By using singleton types to accurately track pointers, and aliasing constraints to model the shape of the store, our type system can represent sharing and ...
  49. [49]
    Lecture 19: Mutation, aliasing and testing
    This ability to “share” a single object between multiple data structures, and access it via multiple names, is called aliasing. Now that we have mutation, ...
  50. [50]
    6.5 Aliasing and “Mutation at a Distance”
    Aliasing occurs when variables refer to the same object, allowing 'mutation at a distance' where modifying one variable changes the object shared by others.
  51. [51]
    Object-oriented programming: Some history, and challenges for the ...
    By the late 1980s, objects had attracted significant industrial interest. Many different object-oriented languages had been developed, differing in the weight ...
  52. [52]
    [PDF] Data Abstraction and Hierarchy - Department of Computer Science
    This paper discusses the ... and McGraw Hill, 1986. 12. Liskov, B., and Zilles, S. 'Programming with abstract data types”. fioc. o j ACM SIGPLAN.Missing: original | Show results with:original
  53. [53]
    [PDF] Reasoning about Java Programs with Aliasing and Frame Conditions
    Jun 30, 2021 · A main issue is to deal with possible aliasing between objects and to handle correctly the frame conditions limiting the part of memory that a ...
  54. [54]
    A Relational Program Logic with Data Abstraction and Dynamic ...
    Jan 10, 2023 · For an object-based language with dynamic allocation, we introduce a relational Hoare logic with stateful frame conditions that formalizes ...
  55. [55]
    [PDF] Ownership Domains: Separating Aliasing Policy from Mechanism
    Abstract. Ownership types promise to provide a practical mechanism for enforcing stronger encapsulation by controlling aliasing in object-.
  56. [56]
    [PDF] Using Move Semantics in C++ to Minimize Aliasing and ... - CSE Portal
    The reason for this limitation is that structs in Swift are copied lazily (sometimes called “copy-on-write”), so making them immutable allows Swift to offer ...
  57. [57]
    References, Aliasing, and Immutable Objects - Programming 2
    One way to avoid errors caused by aliasing is to make classes immutable. ... Copying the reference to an immutable object is therefore conceptually equivalent to ...
  58. [58]
    [PDF] Stacked Borrows: An Aliasing Model for Rust
    The core idea of the model is to implement a dynamic version of the borrow checker, the part of the Rust type checker that enforces the aliasing rules for ...
  59. [59]
    [PDF] Asymptotic Time Complexity and Intro to Abstract Data Types
    Algorithms that have non-appreciable space complexity are said to be in-place ... Abstract Data Type (ADT) vs. Data Structures. • Data processed by an ...
  60. [60]
    [PDF] Abstract Data Types and Stacks
    are different in terms of time and space complexity. ... – Choosing a specific data type may yield better space complexity but worse time complexity.
  61. [61]
    [PDF] PRIORITY QUEUES
    the worst case time complexity of these methods is. O(logn). • Thus each phase takes O(nlogn) time, so the algorithm runs in O(nlogn) time also. • This sort ...
  62. [62]
    [PDF] Lecture 11 - Amortized Analysis - MIT OpenCourseWare
    Data structures typically support several different types of operations, each with its own cost (e.g., time cost or space cost). The idea behind amortized ...
  63. [63]
    [PDF] Comparison-based Lower Bounds for Sorting
    Theorem 5.1 Any deterministic comparison-based sorting algorithm must perform Ω(nlog n) com- parisons to sort n elements in the worst case. Specifically, for ...
  64. [64]
    On understanding types, data abstraction, and polymorphism
    Our objective is to understand the notion of type in programming languages, present a model of typed, polymorphic programming languages that reflects recent ...
  65. [65]
    [PDF] The Standard Template Library - Stepanov Papers
    Oct 31, 1995 · A. A. Stepanov and M. Lee, “The Standard Template Library,” Technical Report HPL-94-34, Hewlett-. Packard Laboratories, April 1994. B ...
  66. [66]
    Free and bound generics: two techniques for abstract data types in ...
    Abstract. A description of two fundamentally distinct techniques for the implementation of abstract data types within Modular C, a preprocessor extension of C.
  67. [67]
    How C++ Templates Are Used for Generic Programming
    Jan 30, 2020 · In this study, we conduct an experiment to investigate the use of templates in practice. We analyze 1,267 historical revisions of 50 open source ...