A UsefulProgrammingLanguage is one that (simultaneously):
- provides PrimitivesAndMeansOfComposition
- to meet useful functional requirements (as demanded by a domain)
- while also meeting a variety of pervasive concerns, including:
- performance
- efficiency: ability to achieve high performance with very few resources
- utilization: ability to use full power of machine to achieve high performance
- latency: time between a cause and a given effect. There is hardware latency and software latency; a good programming language should allow minimizing total latency, which requires taking full advantage of hardware capabilities.
- multi-dimensional: space, cpu, power-consumption, bandwidth, latency
- reliability
- robust: a system is robust if it keeps working even in adverse conditions. This includes working under contract violations (where programmers mess up). In an open system, robustness is necessary for security - and vice versa - due to malicious coders (denial-of-service attacks, etc.) Robustness for dataflows and event-flows is aided by supporting such techniques as failover, redundancy, caching, and GracefulDegradation - automatically switching to another service, possibly in stages, and even falling back on cached values when the primary services are disabled.
- resilient: a system is resilient to the degree that it quickly and completely recovers from adverse conditions. Poor resilience requires manual intervention restarting whole applications, maybe the whole computer, or possibly even a whole network of computers (and starting them up in a particular order), to recover from error. It might require reformatting a drive. More resilient systems are self-healing (i.e. quickly recovering from fallbacks or failure), involve resetting the minimum possible.
- disruption tolerant
- graceful degradation:
- resilient: recovers quickly, correctly, and automatically once source of problem eliminated
- available: uptime ratings (how many "nines"?)
- predictability
- temporal: ability to predict temporal properties of a process
- realtime: ability to bind latencies (both upper and lower bounds) for a given process
- terminating: weaker than realtime; ability to say that a given process will terminate in certain ways.
- synchronization: ability to ensure two otherwise-independent processes have the same latencies
- embedded: ability to bind space costs (upper bounds) for a continuous process
- clueless programming: ability to know the characteristics of a composed system without knowing implementations of the components. (i.e. cannot use locks for concurrency since two components using locks might be independently correct but then deadlock when composed)
- reliability: ability to prove certain forms of resilience or robustness
- partial-failure handling: ability to predict how system behaves under partial failures from end-to-end.
- consistency: ability for different observers to agree on a property. (Implies consensus, not determinism.)
- bounded inconsistency: bounded inconsistency in a distributed observer system.
- eventual consistency: unbounded inconsistency, with the provision that if updates stop then everyone will eventually reach a consensus on what they should be seeing.
- determinism: lack of observable randomness; given inputs and initial state, output and final state are fully specified. Does not preclude non-observable non-determinism.
- modularity
- delay of choice: code defined outside module can affect module
- component packaging: provision of software units
- matchmaking and linking: ability to meet logical demands from one software unit to another (i.e. "I need HTTP access" is met by "I provide HTTP access" by examining a repository of software components).
- live services: ability to hook into 'real' systems
- confinement: ability to logically replace or intercept access to 'real' systems without modifying the accessing code.
- maintenance
- changing requirements
- changing environment: new hardware, new OS
- backwards compatibility
- system administration
- distributed components
- install: distribution of components
- uninstall: ability to cleanly remove or eliminate unnecessary components after installing them
- dependency management (avoiding DllHell)
- ConfigurationManagement
- PolicyInjection
- security - a variety of environmental concerns
- confinement: limiting the damage from running someone else's code on your machine
- authority: end-to-end ensuring that operators do no more than they are allowed
- privacy: protecting secrets of both users and businesses that need to distribute things. two-sided DigitalRightsManagement.
- robust privacy: protects against accidental leaks by programmers and users, i.e. by having well-defined secrecy-violation exceptions, by censuring, by constraining automatic distribution based on secrecy.
- resilient privacy: helps patch up after a programmer or user leaks data; doable via auditing, WebOfTrust, cutting off unauthorized systems quickly.
- access: ensuring availability of service to authorized users in presence of external attempts at attack or sabotage
- stealth: limiting noisy communications in case of eavesdropping or military purpose
- anonymity: resistance to tracking communications between a data-source and a subscription
- without requiring much SelfDiscipline or foresight
- composition and reuse of code written originally for some other purpose
- scales to large numbers of programmers
- premature abstraction shouldn't hurt performance (i.e. ability to 'flatten' abstractions in a staged compilation)
- premature optimization shouldn't hurt abstraction (i.e. with compositional gotchas, like deadlocks)
- 'clueless' programming: programmers should be able to remain ignorant of implementation details
- 'iterative' or 'exploratory' programming: programmers must be able to learn and achieve progress with the 'write sloppy then fix' approach
- stigmergy: programmers make mistakes, so the language (and IDE) would do well to automatically guide a collection of programmers to fixing the mistakes rather than burying them. (May benefit from FirstClass support for UnitTests to allow ZeroButtonTesting and other features)
- LazinessImpatienceHubris in programmers
- and without requiring a SufficientlySmartCompiler
- implementable: no language primitive shall involve any 'magic'; ideally, the implementation of each primitive is simple and straightforward.
- analyzable: designed for certain analyses to improve reliability, security, performance, etc. RicesTheorem suggests delaying TuringEquivalency as far to the edges of the language as possible
- optimizable: designed to support certain transforms (like TailCallOptimization, PartialEvaluation code elimination, operation reordering) without hurting semantics or modularity. Here it helps if SideEffects are delayed as far to the edges of the language as feasible (EventualSideEffects).