Scala/Java/C# Cheat Sheet
Using scala/java cheat sheet from this article by Ken Scambler. Adding C# equivalents.
Annotation Declarations
Scala
trait Foo extends StaticAnnotation {
}
Java
@interface Foo {
}
C#
class Foo : System.Attribute {
}
- There is no special syntax for annotation definitions.
- An annotation has to extend scala.Annotation, or one of its sub-traits.
- Scala’s compiler will stitch it into the necessary bytecode form for use in Scala or Java.
Annotation Use
Scala
@Foo
class Blah {
@Stuff
def doStuff(): Unit = ()
}
Java
@Foo
public class Blah {
@Stuff
public void doStuff() {}
}
C#
[Foo]
public class Blah {
[Stuff]
public void doStuff() {}
}
- Same annotation usage syntax.
- Annotations are not used very often in Scala.
- The extra power of lambdas, types and implicits means that the extra-linguistic meta-programming that they are required for in Java often doesn’t need to happen.
- Annotations can nest, like in Java.
Array Access
Scala
numbers(0)
Java
numbers[0]
C#
numbers[0]
- There is no special syntax for arrays.
- Anything defining an apply() method can use function-like syntax like this.
Array Assignment
Scala
numbers(0) = 5
Java
numbers[0] = 5
C#
numbers[0] = 5
- There is no special syntax for arrays.
- Anything defining an update() method can use assignment syntax like this.
Array Creation
Scala
val strs = Array("a", "b")
Java
String[] strs = new String[] {"a", "b"}
C#
string[] strs = {"a", "b"}
- Arrays don’t have privileged syntax; they look the same as other generic collections.
- Only use them if you need co-location in memory for high performance.
- Instead of using “new”, we are calling the factory function on the Array object.
- Abstracts over the different kinds of JVM array representations int[], Object[], long[], etc, using black magic.
Autoboxing
Scala
val a: AnyRef = 4 //box
val b: Int = a.asInstanceOf[Int] // unbox
Java
Integer a = 4; // box
int b = a; // unbox
C#
Int32 a = 4; // box
int b = a; // unbox
- Autoboxing and unboxing happens automatically and invisibly.
- See Primitives.
Builder
Scala
class Point(val x: Int = 3, val y = 77)
// x = 5, y = 77
new Point(x = 5)
Java
public class Point {
private final int x, y;
static class Builder {
int x = 0;
int y = 0;
public void withX(int x) {
this.x = x;
}
public void withY(int y) {
this.y = y
}
public Point build() {...}
}
public int getX() {
return x;
}
public int getY() {
return y;
}
// and on and on with more fields
}
C#
public class Point
{
public int X { get; }
public int Y { get; }
static class Builder
{
static int x, y = 0;
public static void withX(int xIn) {
x = xIn;
}
public static void withY(int yIn) {
y = yIn;
}
public static Point Build() {...}
}
}
}
- Scala has named and default parameters.
- You can use this with regular constructors and factory methods, no need for builders.
Casts
Scala
myFruit.asInstanceOf[Banana]
Java
(Banana)myFruit
C#
(Banana)myFruit
- Casting doesn’t have a special syntax, it is a method.
- The syntax is deliberately verbose, to discourage casting.
- Casts are not very idiomatic Scala; mostly the type system should protect you from having to lie to it.
Class Declaration
Scala
class Gumble
Java
public class Gumble {}
C#
public class Gumble {}
- Everything is public by default.
- Don’t need braces if there’s no content.
Class implementing interfaces/mixins
Scala
class Shoe extends Shineable
with Cobbleable with Wearable
Java
public class Shoe implements
Shineable, Cobbleable, Wearable {}
C#
public class Shoe : Shineable, Cobbleable, Wearable {}
- The first thing always says “extends”, even if it is a trait.
- “with” for everything else.
- This determines the order in which trait mixins are applied.
Class with constructor, binding to instance variables with accessors
Scala
class Point(val x: Int, val y: Int)
Java
public class Point {
private final int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int x() {
return x;
}
public int y() {
return y;
}
}
C#
public class Point {
public readonly int x;
public readonly int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
- Adding “val” makes the constructor arg bind to a field of the same name.
- “Instance variables” are actually hidden; what you call is always an accessor method, that can be overridden.
Class with constructor, superclass
Scala
class Gumble(id: String) extends Foo(id)
Java
public class Gumble extends Foo {
public Gumble(String id) {
super(id)
}
}
C#
public class Gumble : Foo
{
public Gumble(String id) : base(id) {}
}
- Primary constructor goes in the declaration.
- Type comes after the identifier.
Enums
Scala
// Algebraic Data Type (ADT)
sealed trait Suit
case object Spades extends Suit
case object Hearts extends Suit
case object Clubs extends Suit
case object Diamonds extends Suit
val suit: Suit = Spades
// or
// Enumeration class
object Suit2 extends Enumeration {
val Spades, Hearts, Clubs, Diamonds = Value
}
val suit2: Suit2.Value = Suit2.Spades
Java
enum Suit {SPADES, HEARTS, CLUBS, DIAMONDS}
Suit suit = Suit.SPADES;
C#
enum Suit { SPADES, HEARTS, CLUBS, DIAMONDS }
Suit suit = Suit.SPADES;
- Scala doesn’t directly support enums; one of the few things in Java that can’t be generated from Scala. People constantly complain about this, but you really don’t need them.
- There are two techniques commonly used; Algebraic Data Types, which are more general and powerful, and the Enumeration mixin, which is less powerful.
- ADTs are a closed hierarchy of ordinary classes and objects; here we are using top-level objects, because we require no parameters.
- “case class” and “case object” is syntax sugar that generates fields, hashcode, equals, toString and factory methods. They are ordinary classes/objects that you could otherwise have defined by hand. Here, “case object” just gives us a toString() the same as the identifier name.
- The Enumeration mixin defines a type Value; the Value method creates a new value of type Value.
- Notice that unlike most languages, comma-separated declarations get assigned to every variable in the list, not just the last one.
- Usually you would prefer ADTs; the Enumeration mixin is quite limited in usage.
Equality (value)
Scala
any1 == any2
Java
obj1.equals(obj2);
primitive1 == primitive2;
C#
obj1.Equals(obj2);
primitive1 == primitive2;
- == is a method that everything supports.
- It calls the equals() method on objects.
- It checks value equality on primitives.
- It is null-safe.
Equality (reference)
Scala
obj1 eq obj2
Java
obj1 == obj2;
C#
obj1 == obj2;
- eq is a method that all objects (any class under AnyRef) support.
- Reference equality is not usually used in functional programming.
- If the reference provides object identity, then it implies that the state of the object mutates over time.
- In FP, identity is usually modelled outside of object instances.
Factory
Scala
() => Foo
Java
public interface FooFactory {
public Foo createFoo()
}
C#
public interface FooFactory {
public Foo createFoo()
}
For Loop
Scala
// Low level equivalent
var i = 0
while (i < max) {
doStuff(i)
i += 1
}
// Index counting equivalent
for (i <- 0 until max) {
doStuff(i)
}
// Obtain index alongside item with combinators
for ((item, i) <- myList.zipWithIndex) {
doStuff(item, i)
}
Java
for (int i=0; i < max; i++)
{
doStuff(i);
}
C#
for (int i = 0; i < max; i++)
{
doStuff(i);
}
- There’s no direct equivalent to the low-level for loop; you would need to use while.
- No one has used this in Java since 1999 anyway.
- You can use a for-comprehension if you just want run through a range.
- start.to(includedEnd).by(step) and start.until(excludedEnd).by(step) are the most common methods used to create range objects.
- The “to” and “until” methods are supported on all numeric types.
- The range is a collection, although it doesn’t explicitly store all of the numbers in range, of course.
- At the cost of an extra iteration, the most concise way to obtain the index alongside elements in a sequence is zipWithIndex.
- “0 until max” is the same as “0.until(max)”. Any instance method can be written in operator style.