views:

416

answers:

5

I decided to create this question to have a single source for all things syntactic sugar in Scala. I feel these details are some of the things most frustrating to starting users and are hard to search for since most/all of them are purely symbols and are thus hard to search for without knowing the name of the concept.

TODO:

  • implicit conversions
  • _ syntax for anonymous functions
  • Other things I'm forgetting
+13  A: 

Basics:

(sorry about the c's before the code blocks, the parser seems to be acting up)

  • a b is equivalent to a.b
  • a b c is equivalent to a.b(c), except when b ends in :. In that case, a b c is equivalent to c.b(a)

  • a(b) is equivalent to a.apply(b) This is why the following definitions for an anonymous functions are identical:

c

val square1 = (x: Int) => x*x
val square2 = new Function1[Int,Int] {
  def apply(x: Int) = x*x
}

When calling square1(y), you are actually calling square1.apply(y) which square1 must have as specified by the Function1 trait (or Function2, etc...)

  • a(b) = c is equivalent to a.update(b,c) Likewise, a(b,c) = d is equivalent to a.update(b,c,d) and so on.

  • a.b = c is equivalent to a.b_=(c). When you create a val/var x in a Class/Object, Scala creates the methods x and x_= for you. You can define these yourself, but if you define y_= you must define y or it will not compile,

e.g.

scala> val b = new Object{ def set_=(a: Int) = println(a) }
b: java.lang.Object{def set_=(Int): Unit} = $anon$1@17e4cec

scala> b.set = 5
<console>:6: error: value set is not a member of java.lang.Object{def set_=(Int): Unit}
       b.set = 5
         ^

scala> val c = new Object{ def set = 0 ; def set_=(a:Int) = println(a) }
c: java.lang.Object{def set: Int; def set_=(Int): Unit} = $anon$1@95a253

scala> c.set = 5
5
  • -a corresponds to a.unary_- Likewise for +a,~a, and !a
  • a <operator>= b, where <operator> is some set of special characters, is equivalent to a = a <operator> b only if a doesn't have the <operator>= method,

e.g.

class test(val x:Int) {
  def %%(y: Int) = new test(x*y)
}

var a = new test(10)
a.x // 10
a %%= 5 //equivalent to a = a %% 5
a.x // 50
Jackson Davis
+7  A: 

In addition to Jaxkson's answer:

  • type F[A,B] can be used as A F B.

For example:

type ->[A,B] = (A,B)
def foo(f: String -> String)
  • Using => type in a method definition makes the compiler wrap expressions inside the method call in a function thunk.

For example

def until(cond: => Boolean)(body: => Unit) = while(!cond) body

var a = 0
until (a > 5) {a += 1}
IttayD
I didn't actually know about that first syntax, interesting. This is why we need a consolidated page like this.
Jackson Davis
+4  A: 

Extractors:

There are 2 methods used for extractors, unapply and unapplySeq. These are used in multiple variable assignments and pattern matching.

  • The first use case is where unapply takes the object it is supposed to match and returns a Boolean based on whether or not it matches,

e.g.

trait Gender
trait Male extends Gender
trait Female extends Gender
object Male extends Male
object Female extends Female
class Person(val g: Gender, val age: Int)

object Adult {
  def unapply(p: Person) = p.age >= 18
}

def check(p: Person) = p match {
   case Adult() => println("An Adult")
   case _ => println("A Child")
}

//will print: An Adult since Adult.unapply returns true.
check(new Person(Female, 18))
//will print: A Child as it falls through to the _ case.
check(new Person(Male, 17))

Honestly I dont really get the purpose of the above syntax since it can be done almost just as easily by just putting the code in the case statements. Of course if you have a better example, leave a comment below

  • The general case where unapply takes some fixed-number of parameters and returns either an Option[T] for a single parameter or a Option[(p1,p2,...)] for multiple, i.e. a Tuple with the matched values, e.g.

continuing from the above code:

object Person {
  def apply(g: Gender, age: Int) = new Person(g, age)
  def unapply(p: Person) = if(p.age < 0) None else Some((p.g, p.age))
}

//using Person.apply as described in the Basics section
val alice = Person(Female, 30)
val bob = Person(Male, 25)

//this calls Person.unapply(alice), which returns Some((Female, 30)).
//alice_gender is assigned Female and alice_age 30.
val Person(alice_gender, alice_age) = alice

bob match {
   //calls Person.unapply(bob), but sees that g is Male, so no match
   case Person(Female, _) => println("Hello ma'am")
   //calls Person.unapply(bob) and assigns age = bob.age but it doesn't pass
   //the if statement so it doesn't match here either
   case Person(Male, age) if age < 18 => println("Hey dude")
   //so bob falls through to here
   case _ => println("Hello Sir")
}

Person(Male,-1) match {
  //Person.unapply(Person.apply(Male,-1)) returns None because p.age < 0.
  //Therefore this case will not match
  case Person(_, _) => println("Hello person")
  //Thus it falls through to here
  case _ => println("Are you Human?")
}

Note: Case classes do all those apply/unapply definitions for you (as well as other stuff) so use them whenver possible to save time and reduce code

  • unapplySeq This works similarly to unapply as above except it must return an Option of some kind of sequence.

As a quick example,

scala> List.unapplySeq(List(1,2,3))
res2: Some[List[Int]] = Some(List(1, 2, 3))  
Jackson Davis
+4  A: 

Special Classes: Tuples and Symbols

as mentioned by Rahul G, Tuples and Symbols get slightly special syntax.

  • Symbols: the syntax 'x is short for Symbol("x")
  • Tuples: (p1,p2,..,pn) is short for a case class Tuplen[T1,T2,..,Tn](p1,p2,..,pn)

e.g. the following two are equivalent

val tuple1 = ("Hello",1)
val tuple2 = Tuple2[String,Int]("Hello",1)
Jackson Davis
A: 

a b c is equivalent to a.b(c), except when b ends in :. In that case, a b c is equivalent to c.b(a)

I know "> a b c is equivalent to a.b(c)". How can I write a b c for c.b(a)? Could anyone give an example? Much appreciate.

figured it outdef +: (str:String): String = { return str;}