about
Bits Introduction
08/02/2024
Bits Introduction
C++, Rust, C#, Python, JavaScript, and oh my!
1.0 Introduction
History of Programming Languages
Table 1. Language Descriptors
Bst |
Block-Structured: Code composed of blocks delineated with braces or indentations. Each block creates a stackframe for allocation of local resources when thread of execution enters and disposes on exit. Examples: Algol, C, C++, Rust, C#, Java, Python, JavaScript, ... |
Imp |
Imperative: Source code describes steps to execute. Examples: Algol, C, C++, Rust, C#, Java, Python, JavaScript, ... We will focus on imperative languages in these Bits. |
Dcl |
Declarative: Source code specifies results of computation. Examples: Swift, Elixir, Clojure, HTML, SQL, Prolog, Lisp |
Lgc |
Logic Programming: A language that describes program intent with a set of rule clauses that a solution must satisfy through logical reductions, e.g., also Declarative. Examples: Prologue, Mercury, CLP(FD), ... Lisp and Clojure have some logic programming features |
Fun |
Functional: A language that describes program intent with a set of function compositions and specialized data structures. Functions are expected to be first-class, e.g., can be passed to and returned by other functions. Often data is immutable and operations are implemented with recursions. Examples: Lisp, Haskel, ML, OCaml, Clojure, ... Rust, Swift, C#, JavaScript, and Python have some functional features like lamdas (anonymous functions that may capture local data). |
OOP |
Object Oriented Programming: Languages that define objects and support the relationships: inheritance of implementation, composition, and aggregation. Examples: Swift, C#, JavaScript, Java, Ada, C++, ... Rust and Go support inheriting traits or interfaces but do not support inheritance of implementation, e.g., concrete base classes. |
Dyn |
Dynamic typing: Types of variables are determined at run-time by binding to data. Examples: Elixir, R, JavaScript, Python, Perl, Erlang, MATLAB |
Mng |
Managed: Compiles to bitecode that is translated for hosting in a virtual machine. Usually uses garbage collection and may support reflection. Examples: TypeScript, Elixir, Clojure, C#, JavaScript, Java, Python, Erlang |
Table 2. Language History
Language | Created | Bst | Imp | Dcl | Fun | OOP | Dyn | Mng | Comment |
---|---|---|---|---|---|---|---|---|---|
Rust | 2015 | ✓ | ✓ | Rust provides traits but no inheritance of implementation, compiles to native code, and has memory and data race safety by construction. | |||||
Swift | 2014 | ✓ | ✓ | ✓ | ✓ | ✓ | Swift is a multi-paradigm language, supporting both imperative and declarative programming styles.. | ||
TypeScript | 2012 | ✓ | ✓ | ✓ | ✓ | TypeScript is a statically typed language that is based on JavaScript. | |||
Elixir | 2011 | ✓ | ✓ | ✓ | ✓ | ✓ | Elixir is based on the Erlang language with a focus on high performance concurrency. | ||
Go | 2009 | ✓ | ✓ | Go provides interfaces but no inheritance of implementation, and uses garbage collection but does not rely on a virtual machine. | |||||
Clojure | 2007 | ✓ | ✓ | ✓ | Clojure is a functional language that relies on a stack-based virtual machine. | ||||
R | 2000 | ✓ | ✓ | ✓ | ✓ | ✓ | R supports both imperative and functional styles with dynamic typing. It is used to process and display data. | ||
C# | 2000 | ✓ | ✓ | ✓ | ✓ | ✓ | Uses compilation to bitecode then translation to a stack-based virtual machine. Has value, reference, and dynamic types. Also provides Language Integrated Query (LINQ). | ||
Language | Created | Bst | Imp | Dcl | Fun | OOP | Dyn | Mng | Comment |
CSS | 1996 | ✓ | ✓ | Cascading Style Sheets (CSS) is a declarative language used to set styles for web programs. | |||||
JavaScript | 1995 | ✓ | ✓ | ✓ | ✓ | ✓ | Scripting language uses unique execution model with event message queue and stack of function stackframes. Widely used for web programs. | ||
Java | 1995 | ✓ | ✓ | ✓ | ✓ | The first to use compilation to bitecode then translation to a stack-based virtual machine | |||
Python | 1991 | ✓ | ✓ | ✓ | ✓ | ✓ | High-level dynamically-typed scripting language | ||
HTML | 1990 | ✓ | A markup language used to structure content in web pages | ||||||
Haskell | 1990 | ✓ | A lazy-evaluation functional language, often used for type system research | ||||||
Perl | 1987 | ✓ | ✓ | ✓ | ✓ | Interpreted language with strong string handling features using regular expressions | |||
Erlang | 1986 | ✓ | ✓ | ✓ | One of the first modern functional languages | ||||
Ada | 1983 | ✓ | ✓ | ✓ | language developed under DOD contracts with safety focus | ||||
C++ | 1979 | ✓ | ✓ | ✓ | One of the first object-oriented programming languages | ||||
Language | Created | Bst | Imp | Dcl | Fun | OOP | Dyn | Mng | Comment |
MATLAB | 1978 | ✓ | ✓ | ✓ | ✓ | Focus on simulation, numerical computing, and data analysis | |||
SQL | 1970s | ✓ | One of the first data programming languages | ||||||
Prolog | 1972 | ✓ | One of the first logic programming languages | ||||||
C | 1972 | ✓ | ✓ | Designed to write code for Unix | |||||
Pascal | 1970 | ✓ | ✓ | Designed to be a teaching language | |||||
Lisp | 1958 | ✓ | ✓ | ✓ | The first AI language | ||||
Algol | 1958 | ✓ | ✓ | The first modern block-structured language | |||||
Fortran | 1957 | ✓ | One of the earliest high-level languages |
Language Definitions
Table 3. - Definitions
Type and Data definitions | |
---|---|
Data | A configuration of bytes that may be contiguous in stack memory, e.g., int, double, ... or split between a control block in stack memory and a collection of values stored in heap, e.g., string, vector, map, ... |
Variable | A name that is bound to an instance of data. |
Type | A specific structure of data with an allowed set of operations determined by the Type implementation, usually with a class or struct. |
Static type | Type defined at compile time, fixed for the lifetime of program. Type applies to both variable and data. |
Dynamic type | Variable type defined at run-time by binding to functions and data of a given type. Variables can be reset to data of a different type at any time during program execution and may be bound to functions defined at run-time. |
Strict typing | Data may be coerced to a different compatible type only by explicit conversions which usually create new data. |
Weak typing | Data of given type may be coerced to another compatible type, using implicit or explicit casts. Coercions may create new data or may simply reinterpret existing data. |
Generics |
Function f(t:T) or class C<T> of unspecified type T at design time. T is specified
at the time of compilation of the executable it serves.
f(t:T) is a pattern for producing functions, e.g., f(i:int), f(d:double), ..., and C<T> is a pattern for producing classes, e.g., C<int>, C<string>, ... , which are in turn patterns for creating instances, e.g., let c = C<int>::new(); |
Type specific definitions | |
Copy (Value) Type |
Copy construction, assignment, and pass-by-value operations copy values of the source
to the destination.
Source and destination are independent instances.
[ show copy diagram ]
|
Move Type |
Copy construction, assignment, and pass-by-value operations move resource values of
the source to the destination. This is usually just a copy of a pointer to the source's
resources.
The source is no longer valid. Note that this is a change of ownership.
[ show move diagram ]
Source invalidation can be avoided by making a clone for the operation. The clone is invalidated but the source from which it is cloned is still valid. Rust and Python provide facilities to easily build clones. [ show clone diagram ] |
Reference Type |
Copy construction, assignment, and pass-by-value operations copy references pointing to the
source instance (always on the heap) to the destination.
This results in two references to the same heap-based instance.
[ show ref diagram ]
|
Type Relationships | |
Inheritance |
A design process that uses a base type as part of a more specialized derived type,
automatically exposing public members of the base as public members of the derived.
Some languages allow use of base implementation as part of the derived implementation, some languages allow only declarations of base methods to be declarations of the derived. |
Composition |
A design process that uses an instance of a composed child type as a member of the
composing type.
Composition results in the child instance embedded in the memory footprint of the composer. Construction, assignment, and pass-by-value result in two independent instances, e.g., the source and destination1. C++ and Rust types can compose instances of arbitrary types. C# can compose only Value types, e.g., primitive types and arrays and structs of primitive types. Python and JavaScript cannot use composition. All their instances reside in a managed heap where instance and child members have distinct memory locations. |
Aggregation |
A design process that uses a pointer or managed handle to an aggregated type as a
member of the aggregator.
Aggregation results in a child instance placed in a native or managed heap2 at a location distinct from its aggregator type and referred to with a handle. Construction, assignment, and pass-by-value result in two references to the one source instance. C++ and Rust can use composition and aggregation with any type. C# can use composition only with Value types and aggregate only reference types. Python and JavaScript can only use aggregation3 |
|
2.0 Languages
Table 4. - Defining Language Features
Code Repo | C++ | Rust | C# | Python | JavaScript |
---|---|---|---|---|---|
Highs:
All five languages are supported on Windows, Linux, and macOS |
C++ has:
|
Rust has:
|
C# has:
|
Python has:
|
JavaScript has:
|
Lows:
|
C++:
|
Rust:
|
C#:
|
Python:
|
JavaScript:
|
Typical applications |
|
|
|
|
|
Host |
Newly created process
Program Execution |
Newly created process
Program Execution |
Virtual Machine
Stack-based execution engine: Managed Execution Process |
Virtual Machine
Interpreted execution of code blocks: Execution Model |
Virtual Machine
Single-threaded event loop with execution stack and event queue: Event Loop |
Managed |
No
Compiles to native code, supports weak reflection. Very permissive about code operations. Assumes developer understands full consequences of every line of code. |
No
Compiles to native code, supports weak reflection. Restrictions on allowed use of references to enable memory and data race safety by construction. Rust allows pointers only in unsafe blocks1. |
All .Net language codes are compiled to CIL (Common Intermediate Language, similar
to Java Bytecode) and jitted to native code at run-time.
Supports garbage collection and strong reflection. GC eliminates most memory safety issues at the expense of lower performance due to GC operation. |
Parsed to blocks and interpreted
Supports garbage collection and strong reflection. GC eliminates most memory safety issues at the expense of lower performance due to GC operation and interpretation. |
Code jitted and interpreted
Supports garbage collection and strong reflection with caveats. GC eliminates most memory safety issues at the expense of lower performance due to GC operation. |
Types |
Strong static typing
Copy and Move |
Strict static typing
Copy and Move: Bind, Copy, Move, Clone |
Strict static typing and dynamic typing
Value, reference, and dynamic types |
Dynamic typing
All references to heap-based instances. Types apply to data, not variables. |
Dynamic typing
All references to heap-based instances. Types apply to data, not variables. |
Generics | Templates resolved at compile-time, strong support for template metaprogramming, specialization of classes, and overloading of functions. | Generics resolved at compile-time. Generic type can be bound by trait, but no specialization or overloading. |
Generics resolved at run-time. Generic type can be bound by constraints
C# Constraints |
No need for generics due to dynamic typing | No need for generics due to dynamic typing |
Inheritance | Multiple inheritance of implementation | Multiple inheritance of trait declarations (similar to C# interfaces). No inheritance of implementation. | Single inheritance of base class implementation, multiple inheritance of interface declarations. | Multiple inheritance of base class implementations | Single inheritance of implementation using prototype chain |
footnotes: |
|
||||
C++ | Rust | C# | Python | JavaScript |