Programming in Scala Gist 6

Vinu Charanya
vTechNotes
Published in
6 min readMay 25, 2016

These are the key points from the Programming in Scala, Second Edition by Martin Odersky, Lex Spoon, Bill Venners. I wanted to make note of some key points. They may seem broken and not make much sense, if you have not read the book. This is for personal reference. Feel free to correct me if I have interpreted anything wrong in this post.

Chapter 6 — Functional Objects

6.1 A specification for class Rational

A rational number is a number that can be expressed as a ration n/d , where n is the numerator and d is the denominator. The Rational objects can be added, subtracted, multiplied and divided. Rational is going to be an immutable class.

Immutable object trade-offs

  • Easier to reason about because of the lack of complex state space changes.
  • Easily pass around immutable object without having to take defensive copies about the change.
  • Race conditions do not affect the state/value of immutable objects
  • Immutable objects make safe hash table keys.

One major disadvantage is that a small change to a large object graph has to be copied whereas an update could be done in place. This can cause performance bottleneck.

It is not uncommon for libraries to provide mutable alternatives to immutable String.

*In scala classes can take parameters directly. *

6.1 Constructing a Rational Class

  • To make the class immutable, the numerator and denominator must be passed at the time of object creation.
  • In Scala, the class definition takes class parameters and empty classes do not require {}
  • The identifiers n and d in the parentheses after the class name, Rational, are called class parameters.
  • The Scala compiler will gather up these two class parameters and create a primary constructor that takes the same two parameters.
  • The Scala compiler will compile any code you place in the class body, which isn’t part of a field or a method definition in the primary constructor

6.3 Re-implementing the toString method

  • When a class is instantiated, the toString method of the class is called, if undefined it will invoke the java.lang.Object toString which prints the Class name followed with @ and hex number about the memory location.
  • We can override the toString method in the class as follows.

6.4 Checking Preconditions

  • In a rational number denominator should not be zero.
  • The require method takes one boolean parameter. If the passed value evaluates to false, require will throw an IllegalArgumentException

6.5 Adding Fields

Rational with fields
  • Although n and d are class parameters they are not public
  • In order to access the numerator and denominator of the passed rational in the add, we are declaring numer and denom which are fields that are publically accessible.

6.6 Self reference

  • Similar to other languages, this refers to the object instance on which the current executing method is invoked.

6.7 Auxiliary Constructors

  • Constructors other than primary constructors are Auxiliary constructors
  • Auxiliary constructors in scala are defined as def this(…)
  • Every auxiliary constructor must invoke the primary constructor, thus primary constructor is the single point of entry for any class
  • In a scala class only a primary class can invoke a superclass constructor. This is an increased restriction in Scala than java and is really a design trade-off for the greater conciseness and simplicity of Scala’s constructors.

6.8 Private fields and methods

  • Private fields are only accessible within the class and not outside the class
  • In Scala, we can define fields and methods as private

6.9 Defining Operators

  • Instead of adding two rational numbers x add y, it would be better if we can define operators and call the above method as x + y.
  • In order to accomplish that, since Scala lets you define operators as method, we can re define the add method with + as the method name.
  • With Scala’s operator precedence, when two operators like + and * are defined, * will have more preference.

6.10 Identifiers in Scala

  1. Alphanumeric Identifier
  • Starts with a letter or underscore, followed by more letters, digits or underscore.
  • $ is a valid character, but reserved for identifiers generated by the Scala compiler, better not to use to avoid name clashes.
  • Scala follows camel-case and underscores are though valid, not prefered for convenience
  • In Scala a constant just have to start with an upper case letter and it is not the same as val. Val can be redefined on every function call unlike constants. XOffset is preferred over X_OFFSET.

2. An operator Identifier

  • Consists of one or more characters and are printable ASCII characters such as +, :, ?, ~ or #
  • The Scala compiler will internally “mangle” operator identifiers to turn them into legal Java identifiers with embedded $ characters. Eg., :->would be represented internally as $colon$minus$greater.

3. A mixed Identifier

  • Consists of an alphanumeric identifier followed by an underscore and an operator identifier. Eg., unary_+ or myvar_= used as an assignment operator

4. A literal Identifier

  • Consists of an arbitrary string enclosed in backticks (`…`)
  • The idea is put any string that’s accepted by the runtime as an identifier between backticks always resulting in a Scala identifier, even if it is a reserved word.
  • A typical use case eg., accessing the static yield method in Java’s Thread class. Thread.yield() because yield is a reserved word, can be accessed with Thread.`yield`()

6.11 Method Overloading

  • Scala’s method overloading is similar to that of Java’s.
  • It chooses the best overloaded version and if no unique best matching version is found, the compiler rises ambiguous reference error
  • Now with method overloading the above rational objects can be added with x + y instead of x add y

6.12 Implicit Conversions

  • Assume we have an overloaded method that can multiply integers with rationals considering the overloaded method will take the integer passed in as n/1
  • We can do x * 2, but if we wanted to do 2 * x, will not work because now we are calling the multiplication on the integer and not on the rational anymore.
  • To solve this problem in Scala, we can create an implicit conversion that automatically converts interger to Rational numbers
  • The above method defines a conversion method that converts integer to Rational number and the following example works.
  • Note: An implicit conversion needs to be in a scope to work. It won’t work if the above method is placed within the class.
  • Implicit conversion is a very powerful technique to make libraries flexible and convenient

Conclusion

It is good to keep in mind as one designs libraries, it is not merely enabling concise client code, but readable, understandable client code. This chapter gist focused on adding parameters to a class, define several constructors, operators as methods and class customization to make them natural to use.

--

--