proj-plbook-plChAppLangs

Table of Contents for Programming Languages: a survey

todo: combine with plChDomainSpecificLangs


Domain: Finance

MQL (MetaQuotes language) (Metatrader)

For writing programs that communicate with brokers and eg display financial data to users, compute statistics, automate financial trading.

Two versions: MQL4 and MQL5.

" As to the syntax, THE MQL(4/5) language for programming trading strategies is very much similar to the C++ programming language, except for some features:

    no address arithmetic;
    no goto operator;
    an anonymous enumeration can't be declared;
    no multiple inheritance." -- [1], [2]

-- [3]

Data types

" The basic data types are:

    integers (char, short, int, long, uchar, ushort, uint, ulong);
    logical (bool);
    literals (ushort);
    strings (string);
    floating-point numbers (double, float);
    color (color);
    date and time (datetime);
    enumerations (enum).

Complex data types are:

    structures;
    classes." -- [4], [5]

datetimes:

Control flow constructs

conditionals:

looping:

-- [6]

OOP

Links

Composing contracts: an adventure in financial engineering

DSL library of 10 combinators to describe financial contracts compositionally:

https://www.microsoft.com/en-us/research/publication/composing-contracts-an-adventure-in-financial-engineering/

combinators are:

where Observable is a variable.

(note there is also, date "string": date constructor (for use in 'when' and 'until'); i guess you probably also need a 'constant' to make a constant observable, and a True observable to use with 'anytime' to really mean anytime, and double literals for use with 'constant'; in fact the paper describes these: konst: a -> Observable a (for getting a constant), lift: (a -> b) -> Observable a -> Observable b (for applying a unary function to an observable), lift2: (a -> b -> c) -> Observable a -> Observable b -> Observable c (for applying a binary function to an observable), date: Observable Date, and what they call 'instance Num a => Num (Obs a)', which i think just means that they implemented the Num typeclass for Observable)

Things not under an at, anytime, until are like an 'when' at the moment that the contract is acquired.

Haskell syntax (and implementation), examples:

-- zero coupon bond
zcb :: Date -> Float -> Currency -> Contract 
zcb t f k = when t (scaleK f (one k))


-- two contracts bundled together
c1,c2,c3 :: Contract
c1 = zcb (date “1 Jan 2010”) 100 Pounds
c2 = zcb (date “1 Jan 2011”) 100 Pounds
c3 = and c1 c2


-- European option
european :: Date -> Contract -> Contract
european t u = when t (u `or` zero)

-- example of crazy stuff that this can do that other extant things apparently can't
c5 :: Contract
c5 =	european t1 (european t2 c1)

-- american option (golden_handcuff)
shares = zero `or` (scaleK -100 (one Dollar) `and`
	    			scaleK 10 (one MSShare))

golden_handcuff = when t1 (anytime (until t2 shares))

-- payoff based on external observable
c :: Contract
c = when “1 Jan 2002” (scale scale_factor (one Dollar))

scale_factor :: Observable
scale_factor = 1000 * (snow - 10)

Also includes a BDT (binary decision tree) valuation model, primitives include 'discount' and 'snell' processes. Mapping from the compositional primitives to this are:

Links:

Financial application links

Domain: Cryptography

Cryptol

MicroCryptol? (uCryptol):

Domain: Simulation

Domain: visualization

Domain: Chain Code

Called "smart contracts" by many, but I see them as not really 'contracts', just code that runs on blockchains, so i'm adopting Christopher Allen's moniker.

Note: underlying VMs including EVM and Michelson are in plChMiscIntermedLangs.

Solidity

HLL on top of EVM (the Ethereum VM)

Tutorials:

Gotchas:

" for(var i=0; i<arr.length; ++i) {

Solidity is a "statically typed language" with "type inference". In most of these, you'd expect i to be typed as whatever the type of arr.length is, but Solidity does not care, it sees `var i = 0`, 0 fits into a uint8 so a uint8 i is, it'll get promoted during the comparison and if arr has more than 255 elements it'll overflow and the loop is infinite. " [10]

"...the problematically trivial "type inference" of `var`: type is decided based on the smallest type which can hold the literal. So any implicitly typed variable initialised to 0 is an 8-bit unsigned integer." [11]

A small sampling of the issues:

Everything is 256 bits wide, including the "byte" type. This means that whilst byte[] is valid syntax, it will take up 32x more space than you expect. Storage space is extremely limited in Solidity programs. You should use "bytes" instead which is an actual byte array. The native 256-bit wide primitive type is called "bytes32" but the actual 8-bit wide byte type is called "int8".

Strings. What can we say about this. There is a string type. It is useless. There is no support for string manipulation at all. String concatenation must be done by hand after casting to a byte array. Basics like indexOf() must also be written by hand or implementations copied into your program. To even learn the length of a string you must cast it to a byte array, but see above. In some versions of the Solidity compiler passing an empty string to a function would cause all arguments after that string to be silently corrupted.

There is no garbage collector. Dead allocations are never reclaimed, despite the scarcity of available memory space. There is also no manual memory management.

Solidity looks superficially like an object oriented language. There is a "this" keyword. However there are actually security-critical differences between "this.setX()" and "setX()" that can cause wrong results: https://github.com/ethereum/solidity/issues/583

Numbers. Despite being intended for financial applications like insurance, floating point is not supported. Integer operations can overflow, despite the underlying operation being interpreted and not implemented in hardware. There is no way to do overflow-checked operations: you need constructs like "require((balanceOf[_to] + _value) >= balanceOf[_to]);"

You can return statically sized arrays from functions, but not variably sized arrays.

For loops are completely broken. Solidity is meant to look like JavaScript? but the literal 0 type-infers to byte, not int. Therefore "for (var i = 0; i < a.length; i ++) { a[i] = i; }" will enter an infinite loop if a[] is longer than 255 elements, because it will wrap around back to zero. This is despite the underlying VM using 256 bits to store this byte. You are just supposed to know this and write "uint" instead of "var".

Arrays. Array access syntax looks like C or Java, but array declaration syntax is written backwards: int8[][5] creates 5 dynamic arrays of bytes. Dynamically sized arrays work, in theory, but you cannot create multi-dimensional dynamic arrays. Because "string" is a byte array, that means "string[]" does not work.

The compiler is riddled with mis-compilation bugs, many of them security critical. The documentation helpfully includes a list of these bugs .... in JSON. The actual contents of the JSON is of course just strings meant to be read by humans. Here are some summaries of miscompile bugs:

In some situations, the optimizer replaces certain numbers in the code with routines that compute different numbers

Types shorter than 32 bytes are packed together into the same 32 byte storage slot, but storage writes always write 32 bytes. For some types, the higher order bytes were not cleaned properly, which made it sometimes possible to overwrite a variable in storage when writing to another one.

Dynamic allocation of an empty memory array caused an infinite loop and thus an exception

Access to array elements for arrays of types with less than 32 bytes did not correctly clean the higher order bits, causing corruption in other array elements.

As you can see the decision to build a virtual machine with that is natively 256-bit wide led to a huge number of bugs whereby reads or writes randomly corrupt memory.

Solidity/EVM is by far the worst programming environment I have ever encountered. It would be impossible to write even toy programs correctly in this language, yet it is literally called "Solidity" and used to program a financial system that manages hundreds of millions of dollars. " [13] Q: "What is the insane name mangling and case sensitivity that you mentioned there?" A (by SolarNet?): "`Transfer` is an event, `transfer` is a function. This [14] is from TheDAO? attack and is one of the (many) bugs making the attack so terrible.

As for name mangling, read this [15] and see if it seems sane to you.

For bonus points [16], `this.foo()` and `foo()` mean two wildly different things.

I don't even know what they were thinking. " [17]

All state is mutable by default (this includes struct fields, array elements, and locals). Functions can mutate state by default. Both are overridable by explicit specifiers, much like C++ "const", but you have to remember to do so. Even then, the current implementation doesn't enforce this for functions.

Integers are fixed-size and wrap around, so it's possible to have overflow and underflow bugs. Granted, with 256 bits of precision by default that's harder to do than usual... but still pretty easy if you e.g. do arithmetic on two inputs.

Operators have different semantics depending on whether the operands are literals or not. For example, 1/2 is 0.5, but x/y for x==1 and y==2 is 0. Precision of the operation is also determined in this manner - literals are arbitrary-precision, other values are constrained by their types.

Copy is by reference or by value depending on where the operands are stored. This is implicit - the operation looks exactly the same in code, so unless you look at declarations, you don't know what it actually does. Because mutability is pervasive, this can can have far-reaching effects.

Map data type doesn't throw on non-existing keys, it just returns the default value.

The language has suffixes for literals to denote various units (e.g. "10 seconds" or "1000 ether"). This is purely syntactic sugar, however, and is not reflected in the type system in any way, so "10 second + 1000 ether" is valid code.

Statements allow, but do not require, braces around bodies. This means that dangling "else" is potentially an issue, as is anything else from the same class of bugs (such as the infamous Apple "goto fail" bug).

Functions can be called recursively with no special effort, but the stack size is rather limited, and it looks like there are no tail calls. So there's the whole class of bugs where recursion depth is defined by contract inputs.

Order of evaluation is not defined for expressions. This in a language that has value-returning mutating operators like ++!

Scoping rules are inherited from JS, meaning that you can declare variables inside blocks, but their scope is always the enclosing function. This is more of an annoyance than a real problem, because they don't have closures, which is where JS makes it very easy to shoot yourself in the foot with this approach to scoping. " [18] "Just because a contract is mutable doesn't mean that everything needs to be. For starters, not all functions on the contract are supposed to be mutating. Marking those that are as such would catch accidental mistakes when unnecessary mutations happen. Then there's the issue with structs, collections etc all also being mutable by default, which is separate of contracts. Finally, none of this actually requires any mutability at all. A contract could treated as a pure function that takes initial state as input, and returns the new state as output. Such a function can be written without any mutations at all, by constructing the new state piece by piece from the old one. Sure, it would be a more verbose (although functional languages usually offer shortcuts like "give me a copy of this object, but with these fields set to different values", making it not so verbose after all). But on the other hand, it means that you have to explicitly consider the effect of every operation of the contract on every bit of state. "Don't repeat yourself" is not always a good thing - when it comes to security, you often do actually want to make people do redundant things, e.g.: http://www.atlasobscura.com/articles/pointing-and-calling-japan-trains" [19] "

Opinions:

`Transfer` is an event, `transfer` is a function. This [0] is from TheDAO? attack and is one of the (many) bugs making the attack so terrible.

As for name mangling, read this [1] and see if it seems sane to you.

For bonus points [2], `this.foo()` and `foo()` mean two wildly different things.

I don't even know what they were thinking.

[0] http://vessenes.com/deconstructing-thedao-attack-a-brief-code-tour/

[1] http://solidity.readthedocs.io/en/latest/abi-spec.html#

[2] https://github.com/ethereum/solidity/is "

" [31]

Opinionated comparisons:

The biggest issue facing Solidity developers today is the sheer cost of best practices: ensuring you handle overflows right (ie don't use math primitives but call an approved function), planning for upgrades/data export, you name it: you have to use that code and pay that gas. The environment really needs to provide a lot more "free" functionality than it does today to change this reality. " [32]

Specifically, in E and Monte, we can write auditors, which are objects that can structurally prove facts about other objects. A common auditor in both languages is `DeepFrozen?`; writing `as DeepFrozen?` on an E or Monte object causes the `DeepFrozen?` auditor to examine the AST of that object and prove facts.

There's a Monte community member working on an auditor for primitive recursive arithmetic, inspired IIUC primarily by the EVM's failings.

The DAO hack happened because of a bug class known as "plan interference" in the object-capability world; these bugs happen because two different "plans", or composite actions of code flow, crossed paths. In particular, a plan was allowed to recursively call into itself without resetting its context first. EVM makes this extremely hard to get right. E and Monte have builtin syntax for separating elements of plans with concurrency; if you write `obj.doStuff()` then it happens now, but `obj<-doStuff()` happens later.

So, uh, yeah. Smart contracts aren't a bad idea, but Ethereum's not very good. " [33]

Best practices:

Proving correctness:

Yoichi Hirai's summary of his research into Ethereum formal verification as a full-time formal methods researcher at the Foundation: https://github.com/pirapira/ethereum-formal-verification-overview

See especially his formalization of the EVM as Hoare triples in Lem, which is usable from Isabelle: https://github.com/pirapira/eth-isabelle -- very cool stuff, although I have to say that the ostensible complexity and difficulty of his proof verifying an utterly simple wallet contract makes me a bit skeptical of this approach to smart contract correctness: https://github.com/pirapira/eth-is " [34]

Tools and frameworks:

Links:

Bitcoin script

see plChRestrictedLangs

Plutus

see plChRestrictedLangs

Pact

HLL on top of the Kadena blockchain platform.

" Safe by Design

To write safe smart contracts you need a safe language. Pact is immutable, deterministic, and Turing-incomplete, fighting bugs and exploits while offering the full power of a high-level language. Atomic transactions keep your data sane.

Fast, Legible Code

Based on LISP, Pact strikes a balance between low-level directly executable expressions and high-level declarative code. It parses fast and executes faster, and is stored unmodified on the ledger: you always know what code you're running. " [35]

Pact links:

Viper

HLL on top of EVM (the Ethereum VM)

https://github.com/ethereum/viper

note: i think it's been changed to https://github.com/ethereum/vyper , the previous link redirects.

" Viper is an experimental programming language that aims to provide the following features:

    Bounds and overflow checking, both on array accesses and on arithmetic
    Support for signed integers and decimal fixed point numbers
    Decidability - it's possible to compute a precise upper bound on the gas consumption of any function call
    Strong typing, including support for units (eg. timestamp, timedelta, seconds, wei, wei per second, meters per second squared)
    Maximally small and understandable compiler code size
    Limited support for pure functions - anything marked constant is NOT allowed to change the state" [36]

Viper types

Mostly quoted and paraphrased from [37]:

Vyper links

Serpent

https://github.com/ethereum/wiki/wiki/Serpent

https://github.com/ethereum/serpent

Vitalik Buterin considers it obsolete: "PSA: I now consider Serpent outdated tech; not nearly enough safety protections by current standards" [38]

The Serpent language macro system is powerful enough to compute factorial:

Examples:

Opinions:

Links:

Liquidity

HLL on top of Michelson (http://kadena.io/pact/the Tezos VM):

E

"The E programming language has been a vehicle for smart contract and security research for over 20 years." [39]

Typecoin

https://www.msully.net/stuff/typecoin.pdf

"Contracty" smart contract languages

Szabo's 2002 proposal

http://nakamotoinstitute.org/contract-language/

"Contracty" smart contract languages links

Ivy

Links:

Bamboo

"makes state transition explicit and avoids reentrance problems by default"

IELE

https://iohk.io/blog/iele-a-new-virtual-machine-for-the-blockchain

https://github.com/runtimeverification/iele-semantics/blob/master/Design.md

examples:

"The design of IELE was based on our experience with formally defining dozens of languages in K, but especially on recent experience and lessons learned while formally defining two other virtual machines in K, namely..." KEVM and KLLVM.

" Unlike the EVM, which is a stack-based machine, IELE is a register-based machine, like LLVM. IELE also directly supports functions, like LLVM. It has an unbounded number of registers and also supports unbounded integers.

...

Design Changes Relative to EVM

...

Registers are visible only within the function in which they are used. Registers have a lifetime equal to the lifetime of a function call to the function that contains them.

...

A IELE program consists of a list of contracts, where contracts later in the list can create accounts with deployed contracts found earlier in the list. Unlike EVM, in which a contract is a sequence of instructions, a IELE contract consists of a header giving the contract a name, followed by one or more function definitions and optionally one or more external contract

...

...

Static Jumps

IELE no longer has dynamic jump instructions. They are replaced with jumps that take a named label as an argument, and with a call/return mechanism to allow function calls that return to the caller.

    The code within a function contains named labels. Any instruction can be prefixed by a named label that makes this instruction a valid target of a jump.
    The br instruction has two variants. It can be used with a named label as a single argument for unconditional jumps within a function body, or with an additional register holding a condition value for conditional jumps when the condition value is not zero. The instruction prefixed by the named label is the target of the jump. Therefore all jump targets can be known statically.

...

IELE function calls take an arbitrary number of register arguments and return values instead of a memory range.

    IELE has a call instruction used for local calls to other functions within the contract. call takes a function name, an arbitrary number of arguments, and an arbitrary number of register return values, and jumps to the start of the function in the current contract with the corresponding name. It pushes the current instruction position, the values of all local registers, and the register operands of the return values onto the local call stack. The arguments of the call are copied into local registers corresponding to the formal arguments of the function being called. A contract is malformed if the number of results in a local call does not match the number of results returned by the target function.

IELE has a call .. at and a staticcall .. at instruction used for account calls to public functions of other contracts. The target account address is a register operand of these instructions, as is the amount of gas to be spent during the call, and call .. at has an additional operand for the balance to be transferred with the call. call .. at and staticcall .. at also take an arbitrary number of arguments and return values in the form of register operands instead of memory ranges. The arguments are copied into local registers corresponding to the formal arguments of the function being called. The first register operand in the list of return values is the status register. This register will hold the exit status code upon returning from the call. This means that the list of return value registers given to a call .. at or staticcall .. at instruction should be long enough to accept the correct number of values expected to returned by the callee plus the exit status code.

The ret instruction takes an arbitrary number of register operands holding returned values

The revert instruction takes a single register operand. revert always returns from the contract to the callsite of the caller account code, independently of the size of the local stack. It refunds unused gas and returns a value in the first register return value of the call (that is the exit status register), but does not write to the other return values, and it also rolls back the state changes of the contract.

A static account call, done with staticcall .. at, similarly to EVM, should not attempt to change any state in the network (e.g. log, account storage, account creation/deletion) during its execution. If it does, an exception is thrown. (Avoiding state changes also means that no balance can be transferred with the staticcall .. at, which is why call .. at takes one additional parameter).

In all cases, if a mismatch occurs between the number of arguments or return values of a function and the matching call or ret instruction, an exception is thrown.

When an exception is thrown during the lifetime of an account call, the call is terminated and control returns to the callsite of the caller account code, similarly to a revert. Also in a similar fashion to revert, an exit status code is returned in the first register return value of the call (that is the exit status register), while nothing is written to the other return values, and the state changes of the contract are rolled back. However, unlike revert, no unused gas is refunded.

Following is a comprehensive list of exit status codes:

Because they are no longer needed, we remove EVM's CALLDATA* instructions and RETURNDATA* instructions.

Because of security concerns, we remove the EVM's CALLCODE and DELEGATECALL instructions. We provide a different way to more cheaply create many contracts that share code.

Words

Unlike EVM, which uses 32-byte unsigned words, IELE has arbitrary-precision signed words.

    Because words are now explicitly signed, the SDIV, SMOD, SLT, and SGT instructions are removed, and DIV, MOD, LT, and GT are replaced with signed versions.
    An expmod instruction is added to perform exponentiation modulo a particular base, and the MODEXP precompiled contract is removed.
    a twos instruction is added to convert a signed integer into an N-byte twos-complement representation of the number, where N is passed as an argument to the instruction.
    sext (corresponding to EVM's SIGNEXTEND) is changed to convert an N-byte twos-complement representation of a signed number into its signed value, where N is passed as an argument to the instruction.
    Because integers are unbounded, the index operand of byte (corresponding to EVM's BYTE) now counts from the least-significant byte instead of the most-significant.
    In order to reduce gas costs for multiplication and division by powers of two, we introduce an explicit bitwise shift operator. It takes two arguments, and the second is positive for left shift and negative for right shift.

Local Execution Memory

Unlike EVM, which uses a 2^256-cell array of bytes as local execution memory, IELE's local execution memory is a 2^256-cell array of arbitrary-length byte buffers.

    Unbounded signed integers are stored with their MSB first (at offset 0 within the cell).
    There are two variations of the load and store instructions, one that accesses the whole contents of a cell interpreting them as an unbound signed integer, and one that accesses a subrange of the bytes stored in a cell.
    Similar to EVM, the local execution memory is cleared when the currently executing contract returns.

Account Storage

IELE's account storage is an unbound array of unbound signed integers, unlike EVM's storage, which is a 2^256 cell array of 256-bit words. Similar to EVM, IELE's account storage (unlike the local execution memory) is persistent over contract calls and returns and is only cleared when the corresponding account is destroyed.

Instructions and Precompiled Contracts

Unlike EVM, where each instruction is just an opcode operating on the values found on top of the stack, IELE instructions follow a syntax similar to LLVM: each instruction is an opcode followed by some arguments in the form of registers. If the instruction produces a result, it is formed as an assignment where the LHS contains the register(s) to hold the result(s) and the RHS contains the opcode and the arguments. Other changes with respect to EVM include:

    IELE has one integer comparison instruction, namely cmp, that accepts various predicates. In addition to the predicates lt, gt, and eq, which have corresponding EVM instructions, the predicates le, ge, and ne are also supported.
    The IELE instructions for storing in the local execution memory (store) and account storage (sstore) accept two arguments, where the first argument is the value to be stored and the second argument is the index of the memory cell to be updated. This is opposite from the order expected on the stack in the corresponding EVM instructions, but similar to the order used in the corresponding LLVM instruction.
    Various EVM instructions that query local and/or network state (e.g. GAS, BALANCE, etc.) have been replaced by IELE builtins that can be called using the call instruction (e.g. %balance = call @iele.balance(%bank.account)). The names of all IELE builtins start with the prefix @iele., following a convention similar to the LLVM intrinsics. All names for global functions starting with this prefix are reserved: A contract is malformed if it contains user-defined registers and/or functions with names starting with @iele..
    Precompiled contracts in IELE are also invoked using corresponding builtins (e.g. @iele.ecpairing), but should be called using the call .. at instruction and targeting the account with address 1 (e.g. %res = call @iele.sha256 at 1 ( %len, %data ) send %val, gaslimit %gas).

Contract Creation

Unlike EVM, both for ease of verification and due to security concerns, we do not allow smart contracts to create new accounts from dynamically computed code. Accounts can be dynamically created only from code that is part of a previously validated contract, either by copying the complete contract of an account or by instantiating a child contract packaged inside the creating contract. Accounts can be created from completely new code only by top-level blockchain transaction, not by any IELE instructions.

Each externally declared contract should have been defined in the same file and above the contract that externally declares it, otherwise the contract is malformed. As a result of this requirement, the exact code that will be deployed by a create instruction is statically known and available.

A separate instruction, copycreate, is introduced for the case of copying an entire contract, or duplicating your own contract. The copycreate instruction behaves like create, except that instead of taking a contract name, it takes a register operand containing an account address, and deploys the entire contract deployed to said account to the newly created account.

Because we no longer actually need to address portions of code by program counter in order to create contracts, we remove the EVM's CODECOPY and EXTCODECOPY instructions. Because these are also the only remaining instructions which require the code to be addressed by a particular byte offset, we also remove the EVM's PC instruction.

    Transactions that create a contract now explicitly provide the binary data of the contract instead of the binary data of the initialization function. Contracts created in this way still invoke the @init function to initialize the contract. If the contract is malformed, the transaction fails.

Because accounts created by create and copycreate only use code that already exists on the blockchain, they do not have a charge based on code size. This allows for cheap code reuse, without unsafe operations like DELEGATECALL or an explicit notion of shared library code.

...

Design Changes Relative to LLVM

...

Type system

Unlike LLVM, which uses finite-precision words as values of its various integer and floating point types, IELE values are arbitrary-precision words. Moreover, we decided to support initially only one type, int, describing arbitrary-precision integer values. This suffices to capture the functionality of EVM in terms of values. In the future we may add a type system supporting aggregate types (such as arrays and structures) as well as (higher-order) function types, similar to the LLVM type system.

Static Single Assignment (SSA) form

IELE registers are not in Static Single Assignment (SSA) form, meaning that they can be (statically) assigned more than once and that there is no need for IELE phi functions. This departure from the LLVM SSA style was dictated by the fact that IELE, as the target interpreted language for smart contracts, should allow programs to minimize the number of registers they use the consequent gas costs. A compiler that generates IELE can still use an SSA IELE representation internally to ease optimization, but we do not enforce SSA in the final IELE program to allow compiler and/or hand-written code to optimize their register usage.

Control flow

We decided to relax the LLVM restrictions about basic block structure, where code is organized as a control-flow graph of maximal basic blocks with explicit and statically defined successors/predecessors. In IELE, we maintain static labels as the only allowed targets of jumps, but also allow execution to fall through from one block to the next, whereas in LLVM the first instruction of a basic block can only be reached through a jump, and every LLVM block must end with a control flow instruction. We made this decision in order to minimize the size of the code of IELE programs, since these restrictions in LLVM programs usually result in additional branch instructions. Bitwise shift

Because IELE has arbitrary-precision signed integers, bitwise shifts are expressed in terms of a signed shift amount instead of separate shr and shl instructions.

" -- https://github.com/runtimeverification/iele-semantics/blob/master/Design.md

Simplicity

see plChMiscIntermedLangs.txt

EVM

see plChMiscIntermedLangs.txt

LLL

see plChMiscIntermedLangs.txt

iulia

see plChMiscIntermedLangs.txt

Michelson

see plChMiscIntermedLangs.txt

AntShares VM

see plChMiscIntermedLangs.txt

Smart contract language links

Domain: Education about programming languages

COOL

Classroom Object Oriented Language

" for use in an undergraduate compiler course project. While small enough for a one term project, Cool still has many of the features of modern programming languages, including objects, automatic memory management, strong static typing and simple reflection. ... The reference Cool compiler is written in C++, built fully on the public domain tools. It generates code for a MIPS simulator, SPIM. ... As the primary purpose of Cool is instruction, it lacks many of the features common to other, more general programming languages. For instance, the language supports less than comparisons but not greater than. The syntax is very much stripped down, and the "standard library" contains only a few basic classes. Separate compilation is not supported, though the compiler does support multiple source files as input. Every Cool program must define a class Main which must have a no-args main method in which execution flow begins. Namespaces are not supported. ...

A simple program for computing factorials:

class Main inherits IO { main(): Object {{ out_string("Enter an integer greater-than or equal-to 0: ");

    let input: Int <- in_int() in
      if input < 0 then
        out_string("ERROR: Number must be greater-than or equal-to 0\n")
      else {
        out_string("The factorial of ").out_int(input);
        out_string(" is ").out_int(factorial(input));
        out_string("\n");
      }
      fi;
  }};
  factorial(num: Int): Int {
    if num = 0 then 1 else num * factorial(num - 1) fi
  };};

" -- [40]

Links:

Domain: statistical models

STAN

"Q: do you have a recommended guide/textbook on learning stan?... A: As someone who uses Stan - I would recommend reading the Stan reference documentation, it's essentially a textbook. Also, get used to reading the Stan forums on Discourse..." [41]