Update 1: Porting code examples to Ceylon M5 - syntax changes on assignent operator, module definition and support for String Interpolation.
Update 2: Interoperability with java code via .jar containing the Stopwatch class imported as a ceylon module using ceylon import-jar.
Here below a little program in Ceylon that implements 2 modules (+ an extra utility Stopwatch java class from my previous post http://carlosqt.blogspot.com/2011/05/stopwatch-class-for-java.html). There is the module called Fiborial (Fibo(nnacci)+(Facto)rial) that implements the Fibonacci and the Factorial algorithms in two ways, one Recursive (using recursion) and the other Imperative (using loops and states). The second class is just an instance class that does the same thing, but its there just to show the difference between static and instance classes, and finally the execution of the program done by the running function "main".
You can also find 3 more little examples at the bottom. One prints out the Factorial's Series and Fibonacci's Series, the second one just shows a class that mixes both: static and instance members, and finally the third one that uses different return types (including java.math.BigInteger) for the Factorial method to compare the timing and result.
As with the previous posts, you can copy and paste the code below in your Eclipse IDE and start playing and learning with it. This little "working" program will teach you some more basics of the Programming Language.
There are some "comments" on the code added just to tell you what are or how are some features called. In case you want to review the theory, you can read my previous post, where I give a definition of each of the concepts mentioned on the code. You can find it here: http://carlosqt.blogspot.com/2011/01/new-series-factorial-and-fibonacci.html
The Fiborial Program
module com.series.staticfiborial '1.0.0' {
shared import java.base '7';
import blog.series.lib '1.0.0';
}
// Factorial and Fibonacci in Ceylon
// Module "Static Class" using top level members
import java.math { BigInteger { bigone=\iONE, bigzero=\iZERO,
big=\IvalueOf } }
import blog.series.lib { Stopwatch }
// '(private) Static Field' + Initialization
variable String _className = "'Static' Constructor";
// Static Initializer Method instead, but need to be explicitly called.
shared void constructor() {
print(_className);
}
// 'Static' Method - Factorial Recursive
shared BigInteger factorialR(Integer n) {
if (n == 1) {
return bigone;
}
else {
return big(n).multiply(factorialR(n - 1));
}
}
// 'Static' Method - Factorial Imperative
shared BigInteger factorialI(Integer n) {
variable Integer c = n;
variable BigInteger res = bigone;
while (c > 1) {
res = res.multiply(big(c));
c--;
}
return res;
}
// 'Static' Method - Fibonacci Recursive
shared Integer fibonacciR(Integer n) {
if (n < 2) {
return 1;
}
else {
return fibonacciR(n - 1) + fibonacciR(n - 2);
}
}
// 'Static' Method - Fibonacci Imperative
shared Integer fibonacciI(Integer n) {
variable Integer pre = 1;
variable Integer cur = 1;
variable Integer tmp = 0;
for (i in 2..n) {
tmp = cur + pre;
pre = cur;
cur = tmp;
}
return cur;
}
// 'Static' Method - Benchmarking Algorithms
shared void benchmarkAlgorithm(Integer algorithm, Integer[] values) {
Stopwatch timer = Stopwatch();
variable BigInteger facTimeResult = bigzero;
variable Integer fibTimeResult = 0;
if (algorithm == 1) {
print("\nFactorial Imperative:");
// "For" Loop Statement
for (j in 0..values.size - 1) {
if (exists testValue = values[j]) {
// Taking Time
timer.start();
facTimeResult = factorialI(testValue);
timer.stop();
// Getting Time
print(" (``testValue.string``) = ``timer.elapsed``");
}
}
}
else if(algorithm == 2) {
print("\nFactorial Recursive:");
// "While" Loop Statement
variable Integer i = 0;
while (i < values.size) {
if (exists testValue = values[i]) {
// Taking Time
timer.start();
facTimeResult = factorialR(testValue);
timer.stop();
// Getting Time
print(" (``testValue.string``) = ``timer.elapsed``");
}
i++;
}
}
else if (algorithm == 3) {
print("\nFibonacci Imperative:");
// "For Each" Loop Statement
for (testValue in values) {
// Taking Time
timer.start();
fibTimeResult = fibonacciI(testValue);
timer.stop();
// Getting Time
print(" (``testValue.string``) = ``timer.elapsed``");
}
}
else if (algorithm == 4) {
print("\nFibonacci Recursive:");
// "For Each" Loop Statement
for (testValue in values) {
// Taking Time
timer.start();
fibTimeResult = fibonacciR(testValue);
timer.stop();
// Getting Time
print(" (``testValue.string``) = ``timer.elapsed``");
}
}
else {
print("DONG!");
}
}
doc "Run the module `com.series.staticfiborial`."
void run() {
// pass
}
module com.series.fiborial '1.0.0' {
import java.base '7';
shared import com.series.staticfiborial '1.0.0';
}
import java.math { BigInteger }
import java.util { Scanner }
import java.lang { System { sin=\Iin } }
// Import 'Static' Module's 'methods'
import com.series.staticfiborial { staticFiborial=constructor, benchmarkAlgorithm,
facI=factorialI, facR=factorialR,
fibI=fibonacciI, fibR=fibonacciR }
// Instance Class
class InstanceFiborial(className="Instance Constructor") {
// Instance Field and Constructor/Initializer
variable String className;
print(className);
// Instance Method - Factorial Recursive
shared BigInteger factorialR(Integer n) {
// Calling Static Method
return facR(n);
}
// Instance Method - Factorial Imperative
shared BigInteger factorialI(Integer n) {
// Calling Static Method
return facI(n);
}
// Instance Method - Fibonacci Recursive
shared Integer fibonacciR(Integer n) {
// Calling Static Method
return fibR(n);
}
// Instance Method - Fibonacci Imperative
shared Integer fibonacciI(Integer n) {
// Calling Static Method
return fibI(n);
}
}
doc "Run the module `com.series.fiborial`."
void main() {
print("\n'Static' Class");
// Calling 'Static' Class and Methods
// No instantiation needed. Calling method directly from the class
staticFiborial();
print("FacImp(5) = ``facI(5).string``");
print("FacRec(5) = ``facR(5).string``");
print("FibImp(11)= ``fibI(11).string``");
print("FibRec(11)= ``fibR(11).string``");
print("\nInstance Class");
// Calling Instance Class and Methods
// Need to instantiate before using. Call method from instantiated object
value ff = InstanceFiborial();
print("FacImp(5) = ``ff.factorialI(5).string``");
print("FacRec(5) = ``ff.factorialR(5).string``");
print("FibImp(11)= ``ff.fibonacciI(11).string``");
print("FibRec(11)= ``ff.fibonacciR(11).string``");
// Create a (generic) list of integer values to test
// From 5 to 50 by 5
Integer[] values = [
for (i in 5..50)
if (i%5==0) i
];
// Benchmarking Fibonacci
// 1 = Factorial Imperative
benchmarkAlgorithm(1, values);
// 2 = Factorial Recursive
benchmarkAlgorithm(2, values);
// Benchmarking Factorial
// 3 = Fibonacci Imperative
benchmarkAlgorithm(3, values);
// 4 = Fibonacci Recursive
benchmarkAlgorithm(4, values);
// Stop and exit
print("Press any key to exit...");
value s = Scanner(sin);
//String line = s.nextLine();
s.nextLine();
s.close();
}
And the Output is:
Printing the Factorial and Fibonacci Series
module com.series.fiborialseries '1.0.0' {
shared import java.base '7';
}
import java.math { BigInteger { bigone=\iONE,
big=\IvalueOf } }
class Fiborial() {
// Using a StringBuilder as a list of string elements
shared String getFactorialSeries(Integer n) {
// Create the String that will hold the list
value series = StringBuilder();
// We begin by concatenating the number you want to calculate
// in the following format: "!# ="
series.append("!");
series.append(n.string);
series.append(" = ");
// We iterate backwards through the elements of the series
variable value i = n;
while (i > 0) {
// and append it to the list
series.append(i.string);
if (i > 1) {
series.append(" * ");
}
else {
series.append(" = ");
}
i--;
}
// Get the result from the Factorial Method
// and append it to the end of the list
series.append(factorial(n).string);
// return the list as a string
return series.string;
}
// Using a StringBuilder as a list of string elements
shared String getFibonnaciSeries(Integer n) {
// Create the String that will hold the list
value series = StringBuilder();
// We begin by concatenating the first 3 values which
// are always constant
series.append("0, 1, 1");
// Then we calculate the Fibonacci of each element
// and add append it to the list
for (i in 2..n) {
if (i < n) {
series.append(", ");
}
else {
series.append(" = ");
}
series.append(fibonacci(i).string);
}
// return the list as a string
return series.string;
}
shared BigInteger factorial(Integer n) {
if (n == 1) {
return bigone;
}
else {
return big(n).multiply(factorial(n - 1));
}
}
shared Integer fibonacci(Integer n) {
if (n < 2) {
return 1;
}
else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
}
void run() {
// Printing Factorial Series
print("");
value fiborial = Fiborial();
print(fiborial.getFactorialSeries(5));
print(fiborial.getFactorialSeries(7));
print(fiborial.getFactorialSeries(9));
print(fiborial.getFactorialSeries(11));
print(fiborial.getFactorialSeries(40));
// Printing Fibonacci Series
print("");
print(fiborial.getFibonnaciSeries(5));
print(fiborial.getFibonnaciSeries(7));
print(fiborial.getFibonnaciSeries(9));
print(fiborial.getFibonnaciSeries(11));
print(fiborial.getFibonnaciSeries(40));
}
And the Output is:
Mixing Instance and Static Members in the same Class
In Ceylon it is not possible to define a class with static members. To emulate that you need to create a module with toplevel methods, attributes, and even other instance types/classes.
"There are no static members. Instead, toplevel methods and attributes are declared as direct members of a package. This, along with certain other features, gives the language a more regular block structure." taken from Ceylon documentation.
module com.series.staticfiborial '1.0.0' {}
// Module "Static Class" using top level members
// 'Static' Field'
variable Integer _staticCount = 0;
// 'Static' Read-Only Property/Getter
shared Integer staticCount {
return _staticCount;
}
// 'Static' Initializer Method instead, but need to be explicitly called.
shared void constructor() {
print("\nStatic Constructor ``_staticCount.string``");
}
// 'Static' Method
shared void fibonacci(Integer n) {
_staticCount++;
print("\nFibonacci(``n.string``)");
}
void run() {
// pass
}
module com.series.fiborial '1.0.0' {
import com.series.staticfiborial '1.0.0';
}
import com.series.staticfiborial { staticCount, fibonacci,
staticFiborial=constructor }
// Instance Class
shared class InstanceFiborial(_instanceCount=0) {
// Instance Field and Constructor/Initializer
variable Integer _instanceCount;
print("Instance Constructor ``this._instanceCount.string``");
// Instance Read-Only Property/Getter
shared Integer instanceCount {
return this._instanceCount;
}
// Instance Method
shared void factorial(Integer n) {
this._instanceCount++;
print("\nFactorial(``n.string``)");
}
}
void main() {
// Calling Static Constructor and Methods
// No need to instantiate
staticFiborial();
fibonacci(5);
// Calling Instance Constructor and Methods
// Instance required
value fib = InstanceFiborial();
fib.factorial(5);
fibonacci(15);
fib.factorial(5);
// Calling Instance Constructor and Methods
// for a second object
value fib2 = InstanceFiborial();
fib2.factorial(5);
print("");
// Calling Static Property
print("Static Count = " + staticCount.string);
// Calling Instance Property of object 1 and 2
print("Instance 1 Count = " + fib.instanceCount.string);
print("Instance 2 Count = " + fib2.instanceCount.string);
}
And the Output is:
Factorial using java.lang.Long, java.lang.Double, java.math.BigInteger
module com.series.fiborial '1.0.0' {
shared import java.base '7';
import blog.series.lib '1.0.0';
}
import java.math { BigInteger { bigone=\iONE, bigzero=\iZERO,
big=\IvalueOf } }
import blog.series.lib { Stopwatch }
// Long/Integer Factorial
Integer factorialInt64(Integer n) {
if (n == 1) {
return 1;
}
else {
return n * factorialInt64(n - 1);
}
}
// Double Factorial
Float factorialDouble(Integer n) {
if (n == 1) {
return 1.0;
}
else {
return n * factorialDouble(n - 1);
}
}
// BigInteger Factorial
BigInteger factorialBigInteger(Integer n) {
if (n == 1) {
return bigone;
}
else {
return big(n).multiply(factorialBigInteger(n - 1));
}
}
void main() {
value timer = Stopwatch();
variable Integer facIntResult = 0;
variable Float facDblResult = 0.0;
variable BigInteger facBigResult = bigzero;
print("\nFactorial using Int64");
// Benchmark Factorial using Int64
for (i in (5..50).by(5)) {
timer.start();
facIntResult = factorialInt64(i);
timer.stop();
print(" (``i.string``) = ``timer.elapsed.string`` : ``facIntResult.string``");
}
print("\nFactorial using Double");
// Benchmark Factorial using Double
for (i in (5..50).by(5)) {
timer.start();
facDblResult = factorialDouble(i);
timer.stop();
print(" (``i.string``) = ``timer.elapsed.string`` : ``facDblResult.string``");
}
print("\nFactorial using BigInteger");
// Benchmark Factorial using BigInteger
for (i in (5..50).by(5)) {
timer.start();
facBigResult = factorialBigInteger(i);
timer.stop();
print(" (``i.string``) = ``timer.elapsed.string`` : ``facBigResult.string``");
}
}
And the Output is:









