mirror of
https://github.com/corda/corda.git
synced 2025-02-20 09:26:41 +00:00
Update README
This commit is contained in:
parent
73cbd41a09
commit
eb3c4118ea
215
README.md
215
README.md
@ -1,208 +1,21 @@
|
||||
This source tree contains experimental code that explores a simple DSL for a state transition model with the following characteristics:
|
||||
This source tree contains explorations of various design concepts the R3 DLG is exploring.
|
||||
|
||||
* A blockchain-esque UTXO model is used in which immutable states are consumed as _inputs_ by _transactions_ yielding
|
||||
_outputs_. Transactions do not specify the code to run directly: rather, each state contains a pointer to a program
|
||||
called a _contract_ which defines a verification function for the transaction. Every state's contract must accept
|
||||
for the transaction to be valid.
|
||||
* The language used is [Kotlin](https://kotlinlang.org/), a new general purpose JVM targeting language from JetBrains.
|
||||
It can be thought of as a much simpler Scala, or alternatively, a much more convenient and concise Java.
|
||||
* Kotlin has some DSL-definition abilities in it. These are used to define some trivial extension for the purposes of
|
||||
mapping English requirements to verification logic, and for defining unit tests.
|
||||
* As a base case, it defines a contract and states for expressing cash claims against an institution, verifying movements
|
||||
of those claims between parties and generating transactions to perform those moves (a simple "wallet").
|
||||
|
||||
A part of this work is to explore to what extent contract logic can expressed more concisely and correctly using the
|
||||
type and DSL system that Kotlin provides, in order to answer the question: how powerful does a DSL system need to be to
|
||||
achieve good results?
|
||||
Things you need to know:
|
||||
|
||||
This code may evolve into a runnable prototype that tests the clarity of thought behind the R3 architectural proposals.
|
||||
* The main documentation is in the form of a website in the git repository. Load [the website](docs/build/html/index.html)
|
||||
in the `docs/build/html` directory to start reading about what's included, how to get set up, and to read a tutorial
|
||||
on writing smart contracts in this framework.
|
||||
|
||||
----
|
||||
* The code is a JVM project written mostly in [Kotlin](https://kotlinlang.org/), which you can think of as a simpler
|
||||
version of Scala (or alternatively, a much better syntax for Java). Kotlin can be learned quickly and is designed
|
||||
to be readable, so you won't need to know it very well to understand what the code is doing. If you'd like to
|
||||
add new features, please read its documentation on the website.
|
||||
|
||||
# Kotlin in two minutes
|
||||
There is also Java code included, to demonstrate how to use the framework from a more familiar language.
|
||||
|
||||
Here's a brief description of syntax and features you will see in this code. Kotlin almost always maps directly to Java
|
||||
so it should not be hard to understand. In some cases the Java equivalents are shown.
|
||||
* For bug tracking we use JIRA. For source control we use BitBucket. You should have received credentials for these
|
||||
services as part of getting set up. If you don't have access, please contact Richard Brown or James Carlyle.
|
||||
|
||||
fun foo() = 1234
|
||||
fun foo(): Int = 1234
|
||||
|
||||
Defines a function called foo that returns the single expression 1234. The return type is inferred in the first example.
|
||||
|
||||
val x = 1234 in java: final int x = 1234;
|
||||
var y = "a string" in java: String y = "a string";
|
||||
|
||||
Defines an immutable and mutable variable with inferred types.
|
||||
* There is a mailing list for discussion, brainstorming etc called [r3dlg-awg](https://groups.google.com/forum/#!forum/r3dlg-awg)
|
||||
which you should have been added to already. If you aren't on it, again, please get in touch.
|
||||
|
||||
data class Foo(val x: Int, val y: String) : Bar()
|
||||
|
||||
... in Java:
|
||||
|
||||
public class Foo extends Bar {
|
||||
private int x;
|
||||
private String y;
|
||||
|
||||
public Foo(int x, String y) {
|
||||
this.x = s; this.y = y;
|
||||
}
|
||||
|
||||
public int getX() { return x; }
|
||||
public String getY() { return y; }
|
||||
|
||||
@Override public boolean equals(Object other) { .... }
|
||||
@Override public int hashCode() { .... }
|
||||
@Override public String toString() { .... }
|
||||
}
|
||||
|
||||
Defines a final JavaBean that inherits from Bar, with auto-generated getX(), getY() methods, a constructor that takes
|
||||
both as arguments, equals, hashCode and toString implementations, as well as a useful method called copy() which is a
|
||||
way to duplicate an object with one or more fields changed. Kotlin methods can have named arguments with default values,
|
||||
so copy is auto-generated as:
|
||||
|
||||
fun copy(x: Int = x, y: String = y) = Foo(x, y)
|
||||
|
||||
This avoids the tedious Java builder pattern.
|
||||
|
||||
If the "data" modifier is missing then the equals/toString/hashCode/copy methods are not auto-generated. The reason
|
||||
is that currently the compiler doesn't always know how to handle inheritance scenarios. However java-style get/set/is
|
||||
methods are always generated.
|
||||
|
||||
class Foo(val v: Int)
|
||||
fun List<Foo?>.sum() = filterNotNull().map { it.v }.sum()
|
||||
|
||||
... java equivalent:
|
||||
|
||||
public class Foo {
|
||||
private int v;
|
||||
public Foo(int v) { this.v = v; }
|
||||
public int getV() { return v; }
|
||||
}
|
||||
|
||||
public class FileNameKt {
|
||||
public static int sum(List<Foo> list) {
|
||||
int c = 0;
|
||||
for (Foo foo : list) {
|
||||
if (foo != null) c += foo.getV();
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
Defines a simple class with an int field. Then defines an _extension function_ on List<Foo?>, which is like a static
|
||||
utility method but it appears in auto-complete at the right times, and can be used to integrate externally defined
|
||||
classes e.g. from libraries with language features better. The type Foo? means "a possibly null reference to a Foo". If
|
||||
the question mark is missing then references are guaranteed to be non-null. Kotlin generates nullability assertions
|
||||
in the right places and tracks the nullness of types through the code flow. Finally, this example uses functional
|
||||
programming utilities to express the Java loop in a simpler way. The Kotlin compiler will inline filterNotNull(), map()
|
||||
and sum() so the actual bytecode generated is pretty similar to the Java, however, in this case an additional collection
|
||||
is allocated to hold the results of filtering out the null objects.
|
||||
|
||||
TIPS:
|
||||
|
||||
1. Whenever you see a function call and want to know what it does, you can command/ctrl click on it to treat it like a
|
||||
hyperlink and go to the definition.
|
||||
2. Put the cursor on a function call and press Ctrl-J to pop up the javadoc for it. That's also a fast way to learn
|
||||
how the code works.
|
||||
|
||||
|
||||
object Foo : Bar() {}
|
||||
|
||||
... in java:
|
||||
|
||||
public class Foo {
|
||||
public Foo INSTANCE = new Foo();
|
||||
private Foo() {}
|
||||
}
|
||||
|
||||
Defines a singleton called Foo.
|
||||
|
||||
inline fun <reified T : Foo> List<Any>.doSomething {
|
||||
for (i in this) {
|
||||
if (i is T) {
|
||||
i.someMethodOfFoo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
This is a more complex example you'll only find in the DSL definition. It can't be easily expressed in Java.
|
||||
|
||||
Java does not have reified generics. That means when a generic method or class is compiled, every use of a type
|
||||
variable is replaced with its bound (or Object, if there is no bound). So you can't access the type inside
|
||||
the code itself, which is awkward. Kotlin allows you to duck around this limitation in limited circumstances. Here,
|
||||
we define an extension function that applies to every list that can't contain nulls, which takes a single type
|
||||
variable Y which must either be Foo, or some subclass of Foo. Then for every item that is of that type, it calls
|
||||
a method on it.
|
||||
|
||||
Note that the act of testing the type automatically narrows the type of the variable! Put more simply:
|
||||
|
||||
val x: Any = ....
|
||||
if (x is String)
|
||||
println("it is ${x.length} characters long")
|
||||
|
||||
... in java:
|
||||
|
||||
Object x = ....;
|
||||
if (x instanceof String) {
|
||||
String xAsString = (String) x;
|
||||
System.out.println("it is " + xAsString.length() + " characters long");
|
||||
}
|
||||
|
||||
In Kotlin we don't need the type cast immediately after the check.
|
||||
|
||||
sealed class Foo {
|
||||
class Bar
|
||||
class Baz
|
||||
}
|
||||
|
||||
Defines a class called Foo that has two final inner subclasses. Foo _cannot_ have any other subclasses, so you know
|
||||
that it's safe to do this:
|
||||
|
||||
val f: Foo = ...
|
||||
val result = when (f) {
|
||||
is Bar -> 1
|
||||
is Baz -> 2
|
||||
}
|
||||
|
||||
A "when" expression is like a switch in Java, but it can return something. The compiler will flag an error if we didn't
|
||||
handle all the cases, so if someone adds another case to Foo we'll be sure to update all the places where the type is
|
||||
switched on.
|
||||
|
||||
infix fun Bar.`something long and wordy`(i: Int): Foo = ....
|
||||
val f = bar `something long and wordy` 42
|
||||
|
||||
.... in java:
|
||||
|
||||
public class BarUtils {
|
||||
public static Foo somethingLongAndWordy(Bar b, int i) { ... }
|
||||
}
|
||||
Foo f = BarUtils.somethingLongAndWordy(bar, 42);
|
||||
|
||||
Defines an extension function that has spaces in its name, marked such that it can be used "infix". You cannot define
|
||||
functions with such names in Java, though the JVM allows it. This is purely a syntax tweak but it can make DSLs more
|
||||
easily read.
|
||||
|
||||
Collections: Kotlin uses the ordinary Java collections framework but enhances it with some compiler magic and lots of
|
||||
extension functions. Differences are:
|
||||
|
||||
* List<Foo> is a read-only view of a list of foos that cannot contain nulls.
|
||||
* MutableList<Foo> is the same thing as a java.util.List<Foo>, in that it lets you add/remove elements.
|
||||
* Map<Foo, Bar> is a read-only map of (non-null) Foos to Bars
|
||||
* List.contains and Map.get in Java takes a parameter of type Object, meaning you can accidentally try and look up
|
||||
an entry of the wrong type and the compiler won't stop you. In Kotlin the types are narrowed to catch this error.
|
||||
* You can write "someMap[someKey]" in Kotlin to do get/put on a map.
|
||||
|
||||
|
||||
val m = hashMapOf(
|
||||
"a" to 1,
|
||||
"b" to 2,
|
||||
"c" to 3
|
||||
)
|
||||
println(m["a"])
|
||||
|
||||
in java:
|
||||
|
||||
Map<String, Integer> m = new HashMap<>();
|
||||
m.put("a", 1);
|
||||
m.put("b", 2);
|
||||
m.put("c", 3);
|
||||
System.out.println(m.get("a"));
|
Loading…
x
Reference in New Issue
Block a user