Domains -- The Structure of Programming Languages

Analysis Requirements & Principles architecture:
Paradigms
substance:
Abstractions
structure:
Domains
building blocks: Features surface:
Syntactics
Defining PLs Language
List
foundational safety flexibilized

  1. Common Top-Level Ontology of Programming Languages
  2. Binding: The Semantic Relation for Names
  3. Ambiguity Within The Same Environment
  4. The Connections between Names, References, Values, Variables
  5. The Connections between Classes, Prototypes, Inheritance, Instantiation

 
Disclaimer: This page gives only very few and small, in no way representative glimpses of the structure of programming languages. More such glimpses may be added any time (although currently, this is not very likely). If you have such glimpses or know some references, please don't hesitate to tell me (Ulf Schünemann), likewise if you have any suggestions.

[COInh] Patrick Steyaert, Wolfgang DeMeuter: A Marriage of Class- and Object-based Inheritance Without Unwanted Children; ECOOP'95.


Common Top-Level Ontology of Programming Languages

In the PL literature, the categories of a PL's world (ontology) are called domains. A language can be described structurally at the syntactic and at the semantic level by syntactic/semantic domains and their syntactic/semantic connections.
  1. Syntactic Domains.
    1. lexical: NAMES (see spelling)
    2. grammatical: EXPRESSIONS, STATEMENTS, DECLARATIONS
    Cf. linguistics: syntactic categories (lexical and phrasal).
  2. Static Semantic Domains classify the things that exist in a state of the computation (statics). They are distinguished into [IDC]:
    1. elementary domains: primitive values (integer, string), storage locations
    2. derived domains: Environments, Stores
    3. characteristic domains: DENOTABLES, EXPRESSIBLES, STORABLES
  3. Dynamic Semantic Domains classify the actions/events/processes happening during the computation (dynamics). Eg. "creating [an object]", "selecting" or "navigating", "updating [a variable]", "iterating [over something]", "branching", "jumping", "calling [a subroutine]" or "sending [a message]", "returning a result", "throwing an exception", "waiting for user input", ...

Binding: The Semantic Relation for Names

     syntactic domain    :           semantic domain
                         :
                       binding
                NAME -------------------> DENOTABLE
                  A      :    refers to     A
                  |      :    represents    |
      IDENTIFIER -+      :    symbolizes    +- MEMORY OBJECT
        OPERATOR -+      :    denotes       +- CONCEPTUAL RELATUM
certain keywords -+      :    means         `- DYNAMIC RELATA
         LITERAL -+      :
         NUMERAL -'      :
Names: meaning form
NAME. «A name is a mnemonic character string used to represent something else ...» -->
Names

DENOTABLE is defined as the semantic domain of all those things to which NAMEs can refer. --> Names

Binding. "A binding is an association between two things, such as a name and the thing it names" [ScottP 106]. Bindings can be predefined, explicitly specified by declarations in the program, or implicitly by the (first) use of a name.

syntactic domain    :           semantic domain
                    :
1.        first block's env.
    abc --------------------> int variable with value 3
     `- --------------------> string variable with value "3"
         second block's env.
                    :
                    :
2.           packageA's env.
    abc --------------------> some function
     `- --------------------> another function
             packageB's env.
                    :
                    :
3.              x's env.
    abc --------------------> field abc in x
     `- --------------------> field abc in y
                y's env.
                    :
                    :
4.             struct-env.
    abc --------------------> a record type
     `- --------------------> an integer variable
             untagged env.
                    :
                    :

Ambiguity 1: Vocabulary-Ambiguity. The same word may mean different things in different referencing environments (binding relations). For example, there are two different abcs

  1. in { const int abc = 3; ... print(abc); } and
    in { const string abc = "3"; ... print(abc); }.
  2. in packageX::abc() and in packageY::abc().
  3. in x.abc and in y.abc, where x and y are two different records/objects (of two same or different types).
  4. in f(struct abc) and in f(abc) in the language C, because the former designates the word abs in the "tagged namespace" of structure types, whereas the latter designates the word abs in the "untagged namespace".

Ambiguity Within The Same Environment

Modes of Supposition

A syntactic entity like abc or a[2] in a program text can mean several more or less completely different kinds of things. (Which one is meant depends on the context.) The technical term for this phenomenon is modes of supposition in linguistics/philosophy.
->  meaning
  1. Material supposition. The referencing environment is (the bindings are) not consulted at all. abc means the letters 'a' + 'b' + 'c', and a[2] means the letters 'a' + '[' + '2' + ']'. This is the case for abc and a[2] occuring inside a string-literal: print("Do you know the abc?").
  2. Lexical supposition. abc means an identifier
  3. Conceptual supposition. abc and a[2] mean
  4. Value supposition. abc and a[2] mean
If names like abc (or, more generally, terms like a[2]) are used in a mode other than value supposition, then referential transparency may be lost, as in ordinary language.
->  referential transparency
        

Overloading

«A name that can refer to more than one object in a given scope [referencing environment?] is said to be overloaded. (Contrast this notion to that of aliases, in which two or more names refer to a single object in a given scope.) Semantic rules for overloading require that the specific context of each individual use of the name contain sufficient clues to deduce which meaning (binding) is intended» [Scott 144].
  • Overloading of builtin operators (+, -, ...): in most languages. For example, the name `+' has a different meaning in 2 + 3 than in "abc" + "xyz".
  • Overloading of user-defined function: in Ada, C++, Java, ...
  • Overloading of enumeration constants in Ada:
    lastmonth : Month   := Dec; -- December
    printbase : NumBase := Dec; -- Decimal
Models of Overloading. The intuitive notion of overloading can be localized
syntactic domain    :           semantic domain
                    :
a. in the semantic domain: one overloaded function:
   "+" has a unique meaning -- the inherent overloading-
   ambiguity needs to be resolved statically/dynamically
   only at the place/time where/when "+" is applied.
                    :
    "+"---------------------> fun (x,y:int): int {...}
                    :         & fun (x,y:float): float {...}
                    :         & ...
                    :
b. in the binding relation (predicative overloading):
   "+" has no unique meaning, the ambiguity is apparent.
                    :
    "+"---------------------> fun (x,y:int): int {...}
     `----------------------> fun (x,y:float): float {...}
     `----------------------> ...
                    :
c. in the syntactic domain, as syntactic sugar for indexed names:
   "+" by itself is not given any meaning at all.
                    :
    "+int" ------------------> fun (x,y:int): int {...}
    "+float" ----------------> fun (x,y:float): float {...}
    "+..." ------------------> ...
                    :

Genericity.

«Where a polymorphic subroutine is a single object capable of accepting arguments of multiple types, a generic subroutine allows the programmer to create multiple objects that accept arguments of different types. If desired, Ada allows the resulting objects to share a single, overloaded name. C++ requires them to do so. Clu does not define new names at all, but rather includes the "generic parameters" in every instance of the name (e.g., min[date](my_date))» [
Scott 148].
Models of Genericity. The intuitive notion of genericity can be localized
     syntactic domain    :           semantic domain
                         :
a. in the semantic domain as one polymorphic object (impredicative polymorphism)
                         :
         max --------------------> all t:COMPARABLE. fun (x,y:t): t {...}
                         :
b. in the binding relation: generically overloaded function (Ada, C++):
         max --------------------> fun (x,y:int): int {...}
          |----------------------> fun (x,y:float): float {...}
          |   ...        :           ...
          `----------------------> fun (x,y:date): date {...}
                         :
                         :
c. in the syntactic domain: generic names (whether explicit, as in CLU,
   or with max(1,2) as syntactic sugar for max<int>(1,2))
         max<int> ---------------> fun (x,y:int): int {...}
         max<float> -------------> fun (x,y:float): float {...}
           ...           :           ...
         max<date> --------------> fun (x,y:date): date {...}
                         :
                         :
d. in the semantic domain as one type-to-function mapping,
   and with max(1,2) as syntactic sugar for (max<int>)(1,2)
         max --------------------> fun<t:COMPARABLE>: fun(x,y:t): t {...}
                         :         (a mapping from COMPARABLE types to functions)
                         :
                         :

The Connections between Names, References, Values, Variables

The structure of the characteristic semantic domains shows the difference between Fortran- and Lisp-like languages [IDC] (where 'EXPRESSIBLE' = value of expression ???):
Fortran-like languages:
EXPRESSIBLE = STORABLE
  1. Integer, Variable (or "Location")
  2. Env = Name -> Denotable
    Store = Variable -> Storable
    Procedure = Store -> Store
  3. Denotable = Variable + Procedure
    Expressible = Integer
    Storable = Integer
Lisp-like languages:
EXPRESSIBLE = DENOTABLE
  1. Atom, Nil
  2. Env = Name -> Denotable
    Function = Env -> Expr -> Expr
    List = Nil + (Atom × List)
  3. Denotable = Expressible
    Expressible = Atom + List + Function
      binding(Env)
NAME -------------.
··················v···················
              DENOTABLE
                  A
     .============+============.
     |                         |
 VARIABLE/                 PROCEDURE
 VALUEABLE                     :
     |                         :
     | value(Store) <..........:
     |                 modifies
     v
  INTEGER/
 STORABLE/
EXPRESSIBLE
       binding(Env)
 NAME -------------.        syntactic
···················v·················
              DENOTABLE/     semantic
              EXPRESSIBLE
                   A
     .=============+===========.
     |             |           |
   LIST <------.  ATOM      FUNCTION
     A         |   ^
 .===+===. tail|   |head
 |       |     |   |
NIL     CONS<>-+---'

The structure of the semantic domains also highlights the difference within the object-oriented programming languages between the memory-object meta-model and reference semantics:

(a) The memory-object model:
OBJECT = VARIABLE
The diagram below (with UML ASCII elements) shows the structural view of the C++ model of computation [AFAIK] (C/C++ idos. are in gray):
                               binding
                       NAME -----------------.                            syntactic
  ···········································v·····································
                                         DENOTABLE                         semantic
                                             A
        .==================+========+========"===+=============================+======.
        |                  |        |            |          points-to          |      |
        |     .------> VALUEABLE  ARRAY      POINTABLE <----------------.      |   NAMESPACE
        |     |            A        <>           A                      |      |
        |     |       .===="====.   |   .========"========.             |      |
        |     |       |         |   |   |                 |             |      |
        |     |       |         |   |   |    operations   |             |      |
        |     |  "REFERENCE"  +-----------+ ---------> FUNCTION         |      |
        |     |       `------>|  OBJECT/  |        (incl. =,+,++,[])    |      |
        |     |        refers | VARIABLE  |                             |      |
      TYPE <--|-------------- +-----------+ -----------> VALUE          |      |
      A  A    |  instance-of     A     A         value  STORABLE        |      |
      |  |    |                 /       \                 A  A          |      |
... =='  |    |                /       BASIC             /    \         |      |
         |    |  fields       /       VARIABLE          /  BASIC-VALUE  |      |
       CLASS, `-------<>  STRUCT                       /       A        |      |
       STRUCT,           VARIABLE                   STRUCT     |`== POINTER    |
       UNION <--------- /INSTANCE ----------------> VALUE      `=========== NAMEABLE VALUE
            instance-of                     value                          (numbers, enumerators, ...)

(b) The implicit reference semantics model:
OBJECT not DENOTABLE
The diagram below shows the structural view of the Java model of computation (This seems to be, w.r.t. to the shown parts, about the same as that for Smalltalk and as that for Eiffel but without expanded objects (AFAIK)).
                         binding
                 NAME --------------------.                            syntactic
··········································v·····································
                                      DENOTABLE                         semantic
                                          A
    .=========================+==========="==========+=================+======.
    |                         |                      |                 |      |
   TYPE        .--------> VALUEABLE              .==="===.             |   PACKAGE
   A  A        |              A                  |       |             |
   |  |        |.-------------|-------------> FUNCTION   |             |
   |  |        ||             |                          |             |
   |  |        ||             |        operations        |             |
   | BASIC     ||  inst  +----------+ ----------> OPERATOR-ON-VAR      |
   | TYPE <----||--------| (BASIC)  |             (=, ++, ...)         |
   |           ||   of   | VARIABLE |                                  |
CLASS          ||        +----------+ ----------> (BASIC)-VALUE        |
  ^            ||                          value     STORABLE          |
  |     fields <> operations                            A              |
  |       +-----------+                                 |              |
  |       |  OBJECT/  |<-------------------- POINTER =='|              |
  |       | POINTABLE |   points-to                     |              |
  |       +-----------+                                 `========== NAMEABLE
  | inst.    A    A                                                  VALUE
  | of      /      \                                                 (numbers, ...)
  `--- INSTANCE   ARRAY
Who would like to complete this by corresponding models for full Eiffel, Smalltalk, Ada95, and other languages?


The Connections between Classes, Prototypes, Inheritance, Instantiation

 SUBCLASS-          ROOTCLASS-
DECLARATION        DECLARATION
     |                  |                     syntactic
·····|··················|······························
     | defines          | defines              semantic
     |                  |
     v    inherit       v        instantiate
   DELTA -------+--> GENERATOR --------------> OBJECT
                |       |
                `-------'
following [COInh]
TODO: cf. the operational semantics of object behavior formalized co-algebraically in [
OCCoa p15].
Object = Name -+-> Attribute the external view of a (properly encapsulated) object is an interface allowing to identify some attributes (operations and instance variables) (a partial map)

class-based:
Generator = OID --> Object (a class as) a generator, aka cookie-cutter: takes an OID (Object) and produces an object with that OID as self
instantiate: Generator --> Obj. instantiation produces an object from (a class as) a generator
instantiate(g) = fix(g) where OID = Object
Delta = Obj. --> Generatora subclass delta for subclasses with supercalls: becomes a closed generator if given an object as receiver of supercalls
inherit: Gen. × Delta --> Gen. single inheritance with supercalls means to combine baseclass generator B and delta D into one:
inherit(B,D) = self. B(self) + D( B(self) )(self)
  Gen. × Gen. --> Gen. inheritance without supercalls would mean to combine baseclass generator B and delta generators D into one:
inherit(B,D) = self. B(self) + D(self)

object-based:
Prototype = Prototype --> Obj. a prototype produces an object o after taking a prototype to be used where o uses self as a prototype
instantiate: Prototype --> Obj. instantiation produces an object from (an object as) a prototype, aka generator
instantiate(g) = g(g)
Child = Obj. --> Prototypechild objects take a full object as parent to yield a full prototype
inherit: Proto. × Child --> Proto. object inheritance means to combine parent prototype B and child D into one:
inherit(B,D) = self. B(self) + D( B(self) )(self)

Analysis Requirements & Principles Paradigms Abstractions Domains Features foundational safety flexible typing Syntactics Defining PLs Language List
Ulf Schünemann 140202