What are all the instances of syntactic sugar in Scala?
They 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
Basics:
a b
is equivalent toa.b
a b c
is equivalent toa.b(c)
, except whenb
ends in:
. In that case,a b c
is equivalent toc.b(a)
a(b)
is equivalent toa.apply(b)
This is why the following definitions for an anonymous functions are identical: val square1 = (x: Int) => xx val square2 = new Function1[Int,Int] { def apply(x: Int) = xx }When calling
square1(y)
, you are actually callingsquare1.apply(y)
whichsquare1
must have as specified by theFunction1
trait (orFunction2
, etc...)a(b) = c
is equivalent toa.update(b,c)
Likewise,a(b,c) = d
is equivalent toa.update(b,c,d)
and so on.a.b = c
is equivalent toa.b_=(c)
. When you create aval
/var
x
in a Class/Object, Scala creates the methodsx
andx_=
for you. You can define these yourself, but if you definey_=
you must definey
or it will not compile, for example,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 toa.unary_-
Likewise for+a
,~a
, and!a
a <operator>= b
, where<operator>
is some set of special characters, is equivalent toa = a <operator> b
only ifa
doesn't have the<operator>=
method, for example,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
In addition to Jaxkson's answer:
type F[A,B]
can be used asA 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}
Special Classes: Tuples and Symbols
As mentioned by Rahul G, tuples and symbols get a slightly special syntax.
- Symbols: the syntax
'x
is short forSymbol("x")
- Tuples:
(p1,p2,..,pn)
is short for a case classTuplen[T1,T2,..,Tn](p1,p2,..,pn)
For example, the following two are equivalent.
val tuple1 = ("Hello",1)
val tuple2 = Tuple2[String,Int]("Hello",1)
Extractors:
There are two 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, for example,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 don't 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 anOption[T]
for a single parameter or aOption[(p1,p2,...)]
for multiple, i.e. a Tuple with the matched values, for example, 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 tounapply
as above, except it must return anOption
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))
Anonymous functions:
_ + _
is short for (a, b) => a + b
Context bounds desugar into implicit
parameters, e.g. consider a function that leverages the Monoid
type class:
def suml[T: Monoid](xs: List[T]) = {
val T = implicitly[Monoid[T]]
xs.foldLeft(T.mzero)(T.mplus)
}
where the : Monoid
part is a context bound, gets translated to:
def suml[T](xs: List[T])(implicit evidence$1: Monoid[T]]) = {
...
}
therefore the following compiles, too:
def suml[T: Monoid](xs: List[T]) = {
val T = evidence$1
...
}
来源:https://stackoverflow.com/questions/2662984/what-are-all-the-instances-of-syntactic-sugar-in-scala