Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@renatoathaydes
Last active October 17, 2018 08:29
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save renatoathaydes/7997321 to your computer and use it in GitHub Desktop.
Save renatoathaydes/7997321 to your computer and use it in GitHub Desktop.
Scala VS Ceylon
// This is a comparison between Scala and Ceylon based on this previous comparison I made between Haskell and Groovy:
// https://gist.github.com/renatoathaydes/5078535
// Ex 1. If we have two lists, [2,5,10] and [8,10,11] and we want to get the products of all the possible
// combinations between numbers in those lists, here's what we'd do.
/* SCALA */
for { x <- List(2,5,10); y <- List(8,10,11) } yield x*y
/* CEYLON */
[ for (x in [2,5,10]) for (y in [8,10,11]) x*y ];
// Ex 2. What if we wanted all possible products that are more than 50?
/* SCALA */
for { x <- List(2,5,10); y <- List(8,10,11); if x*y > 50 } yield x*y
/* CEYLON */
[ for (x in [2,5,10]) for (y in [8,10,11]) if (x*y > 50) x*y ];
// Ex 3. How about a list comprehension that combines a list of adjectives and a list of nouns … for epic hilarity.
/* SCALA */
for (noun <- nouns; adjective <- adjectives) yield noun + " " + adjective
/* CEYLON */
{ for (noun in nouns) for (adjective in adjectives) "``noun`` ``adjective``" };
// Ex 4. Let's write our own version of length!
/* SCALA */
def len(xs: List[_]) = (for (_ <- xs) yield 1).sum
/* CEYLON */
Integer len(Anything[] xs) => count { for (x in xs) true };
// Ex 5. Here's a function that takes a string and removes everything except uppercase letters from it.
/* SCALA */
def removeNonUpperCase(s: String) = s.filter(_.isUpper)
/* CEYLON */
function removeNonUpperCase(String s) => String(s.filter(Character.uppercase));
// Ex 6. A list contains several lists of numbers. Let's remove all odd numbers without flattening the list.
/* SCALA */
xxs.map(xs => xs.filter(_ % 2 == 0))
/* CEYLON */
[ for (xs in xxs) xs.select(2.divides) ]
// Ex 7. ... let's try generating all triangles with sides equal to or smaller than 10:
/* SCALA */
val triangles = for (c <- 1 to 10; b <- 1 to 10; a <- 1 to 10) yield (a,b,c)
/* CEYLON */
value triangles = { for (c in 1..10) for (b in 1..10) for (a in 1..10) [a,b,c] };
// Ex 8. ... we'll add a condition that they all have to be right triangles.
// We'll also modify this function by taking into consideration that side b isn't larger
// than the hypothenuse and that side a isn't larger than side b.
/* SCALA */
val rightTriangles = for (c <- 1 to 10; b <- 1 to c; a <- 1 to b; if a*a + b*b == c*c) yield (a,b,c)
/* CEYLON */
value rightTriangles = { for (c in 1..10) for (b in 1..c) for (a in 1..b) if (a^2 + b^2 == c^2) [a,b,c] };
//############### Doing some I/O ###############//
/* NOTE:
In Ceylon, one cannot get away without checking some conditions,
so the Ceylon code shown here is unintentionally making more checks than the Scala code.
The objective is just to write the described functions in the simplest possible way.
*/
// Ex 9. Read file and print its contents
/* SCALA */
import scala.io.Source
println(Source.fromFile("girlfriend.txt").getLines.mkString)
/* CEYLON */
import ceylon.file { ... }
value resource = parsePath("girlfriend.txt").resource;
if (is File resource) {
try (reader = resource.Reader()) {
while (exists line = reader.readLine()) {
print(line);
}
}
}
// Ex 10. Convert a file's text to ALL CAPS text and save it in another file
/* SCALA */
import scala.io.Source
import java.io._
val pw = new PrintWriter(new File("girlfriendcaps.txt"))
try pw.write(Source.fromFile("girlfriend.txt").getLines.mkString.toUpperCase)
finally pw.close()
/* CEYLON */
import ceylon.file { ... }
value inResource = parsePath("girlfriend.txt").resource;
if (is File inResource) {
if (is Nil outResource = parsePath("girlfriendcaps.txt").resource) {
value file = outResource.createFile();
try (reader = inResource.Reader(), writer = file.Overwriter()) {
while (exists line = reader.readLine()) {
writer.writeLine(line.uppercased);
}
}
}
}
// Ex 11. Given a text file containing TO-DO tasks, remove a line chosen by the user from the file
/* SCALA */
import scala.io.Source
import java.io._
val lines = Source.fromFile("text.txt").getLines.toList
for ((line, index) <- lines.view.zipWithIndex) {
println((index + 1) + " - " + line)
}
println("Which one do you want to delete?")
val toRemove = readInt - 1
val pw = new PrintWriter(new File("scala-out.txt"))
try {
for (line <- lines.filterNot(lines.indexOf(_) == toRemove)) {
pw.write(line + "\n")
}
} finally {
pw.close()
}
/* CEYLON */
import ceylon.file { ... }
value resource = parsePath("text.txt").resource;
{String*} fileToList(File file) {
variable {String*} lines = {};
try (reader = file.Reader()) {
while (exists line = reader.readLine()) {
lines = lines.chain({ line });
}
}
return lines;
}
if (is File resource) {
print("Which one do you want to delete?");
value lines = entries(fileToList(resource));
for (index -> line in lines) {
print("``index + 1`` - ``line``");
}
value input = process.readLine();
try (writer = resource.Overwriter()) {
for (index -> line in lines) {
if ((index + 1).string != input) {
writer.writeLine(line);
}
}
}
}
// Ex 12. Create a SQL database with a single table, add data to it, then print the contents of the table
// Based on http://book.realworldhaskell.org/read/using-databases.html
/* SCALA */
/* Using Slick with the Plain SQL API */
import scala.slick.jdbc.{GetResult, StaticQuery => Q}
import scala.slick.jdbc.JdbcBackend.Database
case class Test(id: Int, desc: String) {
override def toString() = id + " - " + desc
}
implicit val getTestResult = GetResult(r => Test(r.<<, r.<<))
Database.forURL("URL-TO-DATABASE") withSession {
Q.updateNA("CREATE TABLE test (id INTEGER NOT NULL, desc VARCHAR(80))").execute
Seq(Test(123, "DB Stuff")).foreach(t => sqlu"""
insert into test values (${t.id}, ${t.desc})
""").execute)
val queryAllTests = sql"select * from test".as[Test]
queryAllTests.foreach(println)
}
/* CEYLON */
/* Using Ceylon standard library ceylon.dbc version 1.0.0 */
import ceylon.dbc { ... }
import javax.sql { DataSource }
value dataSource = /* get and configure a JVM data source */;
value sql = Sql(dataSource);
sql.execute("CREATE TABLE test (id INTEGER NOT NULL, desc VARCHAR(80))");
sql.insert("INSERT INTO test (id, desc) VALUES (?, ?)", 123, "Db Stuff");
value queryAllTests = sql.rows("SELECT * FROM test");
for (test in queryAllTests({})) {
value id = test["id"] else "NULL";
value desc = test["desc"] else "NULL";
print("``id``: ``desc``");
}
//############### GUI Stuff ###############//
// Ex 13. Create a window with a menu-bar containing a File menu with 2 items - About.. and Quit
// At the bottom of the window, there should be a status bar displaying some help for the currently
// selected menu item.
/* SCALA */
//TODO
/* CEYLON */
/* Uses Java Swing directly as no Ceylon alternative exists as of 1.0.0.
Imports omitted for brevity.
*/
class MySwingApp() satisfies Runnable {
shared actual void run() {
value menuBar = JMenuBar();
value frame = JFrame();
frame.title = "Ceylon Swing Demo";
frame.defaultCloseOperation = exitOnClose;
frame.size = Dimension(300, 200);
frame.setLocationRelativeTo(null);
frame.jMenuBar = menuBar;
value panel = JPanel();
panel.layout = BorderLayout();
frame.add(panel);
value statusLabel = JLabel();
value defaultStatus = "Welcome to Ceylon Swing Demo";
value menu = JMenu("File");
menuBar.add(menu);
object aboutListener satisfies ActionListener {
actionPerformed(ActionEvent? actionEvent) => showMessageDialog(null, "This is a Ceylon demo");
}
object aboutMouseEntered extends MouseAdapter() {
mouseEntered(MouseEvent? event) => statusLabel.text = "About Ceylon";
mouseExited(MouseEvent? event) => statusLabel.text = defaultStatus;
}
value aboutItem = JMenuItem("About..");
aboutItem.addMouseListener(aboutMouseEntered);
aboutItem.addActionListener(aboutListener);
object quitListener satisfies ActionListener {
actionPerformed(ActionEvent? actionEvent) => frame.dispose();
}
object quitMouseEntered extends MouseAdapter() {
mouseEntered(MouseEvent? event) => statusLabel.text = "Quit the demo";
mouseExited(MouseEvent? event) => statusLabel.text = defaultStatus;
}
value quitItem = JMenuItem("Quit");
quitItem.addActionListener(quitListener);
quitItem.addMouseListener(quitMouseEntered);
menu.add(aboutItem);
menu.add(quitItem);
panel.add(statusLabel, javaString(south));
frame.visible = true;
}
}
shared void run() {
invokeLater(MySwingApp());
}
@renatoathaydes
Copy link
Author

The last problem is not yet implemented in Scala because I had trouble making the Scala-Swing jar available when running/compiling the Scala code from the command-line... I hope to be able to fix that soon.... if anyone wants to help, please comment!

@oxbowlakes
Copy link

The length of a list in scala is probably more idiomatically one of:

(0 /: xs) { (sum, _) => sum + 1 }

Or

xs.view map (_ => 1) reduceLeft (_ + _)

@oxbowlakes
Copy link

Removing a line from a scala sequence is also more idiomatically (and performantly):

for (line <- lines.toIndexedSeq.patch(toRemove, Nil, 1)) pw.println(line)

Or (often the non-for-comprehension is more readable - IMHO of course)

lines.toIndexedSeq.patch(toRemove, Nil, 1)) foreach pw.println

@oxbowlakes
Copy link

Scala has String interpolation now - so

noun + " " + adjective

Becomes

s"$noun $adjective"

@renatoathaydes
Copy link
Author

Same examples written in Haskell and Groovy: https://gist.github.com/renatoathaydes/5078535

@quintesse
Copy link

@renatoathaydes for example 9 you can probably (didn't test it) do something like:

value resource = parsePath("girlfriend.txt").resource;
if (is File resource) {
    forEachLine(resource, print);
}

or you could maybe do:

value resource = parsePath("girlfriend.txt").resource;
if (is File resource) {
    print(lines(resource));
}

@quintesse
Copy link

And for example 10 you could probably use the createFileIfNil() toplevel method.
Or even better the copyLines() method that copies the contents form one file to another using a filter function.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment