Joerg Viola

Lean. Web. Development.

Scala Pearls for a Dummy

After migrating to Play 2.0, being convinced one can use it with Java alone, I was curious enough to take a look at the Scala side of it. Read about some nice little discoverings of a scla beginner.

Of course, the first contact happens in Play 2.0 templates:

Typesafe

Templates have a signature, types are behind names and type parameters use square brackets. Thus the first line in every template reads like:

1
@(state:State, users:List[User])

Looping

It is simple to loop over any collection:

1
2
3
@for(user <- users) {
  <li><a href="@routes.Publics.user(user.id)">@user.name</a></li>
}

The cool thing is, you don’t need any template extension or whatever to get the looping index. And you have tuples:

1
2
3
4
5
6
@for((user,index) <- users.zipWithIndex) {
  @if(index>0){
      <div class="seperator"></div>
  }
  <a href="@routes.Publics.user(user.id)">@index. @user.name</a>
}

And - you have functions:

1
2
3
4
5
6
@users.zipWithIndex.foreach { (user, index) =>
  @if(index>0){
      <div class="seperator"></div>
  }
  <a href="@routes.Publics.user(user.id)">@index. @user.name</a>
}

or

1
2
3
4
5
<select name="@name" multiple="multiple">
    @options.map { v =>
        <option value="@v._1" @(if(v._3) "selected" else "")>@v._2</option>
    }
</select>

Did you ever require a String representation of a list?

1
columns.map("<td>" + _ + "</td>").mkString

Filtering

Imagine you were to get all Fields of a class with the annotation @Id. Here is the java code:

1
2
3
4
5
6
7
8
  public List<Field> idFields(Class<? extends Object> c) {
      List<Field result = new ArrayList<Field>();
      for (Field f : c.getFields()) {
          if (f.getAnnotation(Id.class)!=null)
              result.add(f);
      }
      return result;
  }

and this is scala:

1
  def idFields(c: Class[_ <: Any]): Seq[Field] = c.getFields().toSeq filter { f => f.getAnnotation(classOf[Id]) != null }

Case classes

Talking about shortness:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
public class Person {
  private String firstName;
  private String lastName;
  private Date birthday;
  private boolean gender;

  public Person(String firstName, String lastName, Date birthday,
          boolean gender) {
      super();
      this.firstName = firstName;
      this.lastName = lastName;
      this.birthday = birthday;
      this.gender = gender;
  }

  public String getFirstName() {
      return firstName;
  }

  public void setFirstName(String firstName) {
      this.firstName = firstName;
  }

  public String getLastName() {
      return lastName;
  }

  public void setLastName(String lastName) {
      this.lastName = lastName;
  }

  public Date getBirthday() {
      return birthday;
  }

  public void setBirthday(Date birthday) {
      this.birthday = birthday;
  }

  public boolean isGender() {
      return gender;
  }

  public void setGender(boolean gender) {
      this.gender = gender;
  }

  @Override
  public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result
              + ((birthday == null) ? 0 : birthday.hashCode());
      result = prime * result
              + ((firstName == null) ? 0 : firstName.hashCode());
      result = prime * result + (gender ? 1231 : 1237);
      result = prime * result
              + ((lastName == null) ? 0 : lastName.hashCode());
      return result;
  }

  @Override
  public boolean equals(Object obj) {
      if (this == obj)
          return true;
      if (obj == null)
          return false;
      if (getClass() != obj.getClass())
          return false;
      Person other = (Person) obj;
      if (birthday == null) {
          if (other.birthday != null)
              return false;
      } else if (!birthday.equals(other.birthday))
          return false;
      if (firstName == null) {
          if (other.firstName != null)
              return false;
      } else if (!firstName.equals(other.firstName))
          return false;
      if (gender != other.gender)
          return false;
      if (lastName == null) {
          if (other.lastName != null)
              return false;
      } else if (!lastName.equals(other.lastName))
          return false;
      return true;
  }

}

is equivalent to:

1
  case class Person(val firstName:String, lastName:String, birthday:Date, gender:boolean);

Built-in singletons

No static methods:

1
2
3
4
5
6
7
class Person {
    ...
  public static Person create() {
     ...
     return person;
  }
}

is equivalent to:

1
2
3
4
5
  case class Person(val firstName:String, lastName:String, birthday:Date, gender:boolean);

  object Person {
      def create = Person();
  }

Traits

Not yet used them, though they look cool!

Comments