Programming in Scala, Fourth Edition (1116) by Martin Odersky & Lex Spoon & Bill Venners

Programming in Scala, Fourth Edition (1116) by Martin Odersky & Lex Spoon & Bill Venners

Author:Martin Odersky & Lex Spoon & Bill Venners
Language: eng
Format: epub
Tags: Scala
Publisher: Artima Press
Published: 2019-04-14T16:00:00+00:00


Listing 20.3 - How abstract vars are expanded into getters and setters.

20.5 Initializing abstract vals

Abstract vals sometimes play a role analogous to superclass parameters: they let you provide details in a subclass that are missing in a superclass. This is particularly important for traits, because traits don't have a constructor to which you could pass parameters. So the usual notion of parameterizing a trait works via abstract vals that are implemented in subclasses.

As an example, consider a reformulation of class Rational from Chapter 6, as shown in Listing 6.5 here, as a trait:

trait RationalTrait { val numerArg: Int val denomArg: Int }

The Rational class from Chapter 6 had two parameters: n for the numerator of the rational number, and d for the denominator. The RationalTrait trait given here defines instead two abstract vals: numerArg and denomArg. To instantiate a concrete instance of that trait, you need to implement the abstract val definitions. Here's an example:

new RationalTrait { val numerArg = 1 val denomArg = 2 }

Here the keyword new appears in front of a trait name, RationalTrait, which is followed by a class body in curly braces. This expression yields an instance of an anonymous class that mixes in the trait and is defined by the body. This particular anonymous class instantiation has an effect analogous to the instance creation new Rational(1, 2).

The analogy is not perfect, however. There's a subtle difference concerning the order in which expressions are initialized. When you write:

new Rational(expr1, expr2)

the two expressions, expr1 and expr2, are evaluated before class Rational is initialized, so the values of expr1 and expr2 are available for the initialization of class Rational.

For traits, the situation is the opposite. When you write:

new RationalTrait { val numerArg = expr1 val denomArg = expr2 }

the expressions, expr1 and expr2, are evaluated as part of the initialization of the anonymous class, but the anonymous class is initialized after the RationalTrait. So the values of numerArg and denomArg are not available during the initialization of RationalTrait (more precisely, a selection of either value would yield the default value for type Int, 0). For the definition of RationalTrait given previously, this is not a problem, because the trait's initialization does not make use of values numerArg or denomArg. However, it becomes a problem in the variant of RationalTrait shown in Listing 20.4, which defines normalized numerators and denominators.



Download



Copyright Disclaimer:
This site does not store any files on its server. We only index and link to content provided by other sites. Please contact the content providers to delete copyright contents if any and email us, we'll remove relevant links or contents immediately.