about
Bits Intro
12/01/2023
Bits Introduction
definitions, language features - C++, Rust, C#, Python, JavaScript
1.0 Introduction
Language Definitions
Table 1. - Definitions
Language Definitions | |
---|---|
Imperative Language |
A language that descibes program intent as a series of commands, often expressed
as function or class method executions.
Examples: Algol, C, C++, Rust, C#, Java, Python, JavaScript, ... We will focus on imperative languages in these Bits. |
Functional Language |
A language that describes program intent with a set of function compositions and
specialized data structures. Functions are expected to be first order, 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, ... |
Logic Programming Language |
A language that describes program intent with a set of rule clauses that a solution must
satisfy through logical reductions.
Examples: Prologue, ... |
Type 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. |
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. |
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. |
Type and Data definitions (tuned to Imperative languages) | |
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(); |
Object 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 2. - 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 MSIL (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 |