The type whose identity is not known precisely can be termed as abstract type.
Scala Abstract Members
A member is said to be abstract if the member does not have a complete definition in the class. These are implemented in the subclasses. For example;
1 2 3 4 5 6 7 |
trait Student { type X def totalmarks(m1:X,m2:X):X val age : X } |
Student trait declares a type X where the type of X is unknown. A method total marks returns type X and members marks1, marks2 are of type X. Here X is called as abstract type.
Now lets us implement the type X in a subclass.
1 2 3 4 5 6 7 |
class Adam extends Student { type X = Int def totalmarks(m1:Int , m2:Int) = m1 + m2 val age = 7 } |
We are creating class Adam that extends the student class and defines type X as Integer. The total marks method add the marks m1 and m2. The age variable is initialized to 7.
Abstract vals
The abstract val takes the form as;
1 2 3 |
val name: String |
The variable name and type is specified here but not the value of the variable name.
For example;
1 2 3 |
val name = "Reena" |
The val declaration can be used in a class when you don’t know the correct value but we know that the value remains unchanged in each instance of the class.
An abstract val declaration constrains its legal implementation – def or val.
For example;
1 2 3 4 5 6 |
abstract class Student { val value:String def method:String } |
An abstract class Student id created with value variable and method with the keyword def.
1 2 3 4 5 6 |
abstract class Rob extends Student { val value:String val method:String } |
A class Rob is created extending Student and the method is defined with the keyword val which is allowed. The code will compile successfully.
1 2 3 4 5 6 |
abstract class Micheal extends Student { def value: String def method:String } |
A class Micheal is created extending the student class and the value and method is defined using the keyword def. This will throw an error as overriding is not allowed. Below image shows the above code execution in scala shell.
Abstract vars
Abstract var defines a name and type but not value. Consider an example which defines two abstract variables – name and age as below.
1 2 3 4 5 6 |
trait Student { var name: String var age: Int } |
The vars declared are equipped with getter and setter methods.
1 2 3 4 5 6 7 8 |
trait Student { def name:String //getter method for name def name_=(n:String) //setter method for name def age:Int //getter method for age def age_=(a:Int) //setter method for age } |
Initializing abstract vals
Abstract vals allows us to provide the details in subclass when missed in superclass. For example;
1 2 3 4 5 6 7 8 9 |
trait student_percent { val obtained: Int val total: Int require(total != 0) val perc = (obtained % total) * 100 override def toString = "Percentage secured is" + perc } |
Here the variables obtained and total are abstract vals and the values are not defined.
1 2 3 4 |
scala> val scale = 5 scale: Int = 5 |
Here we declare variable scale and use them in the trait as below.
1 2 3 4 5 6 7 8 9 10 |
new student_percent { val obtained = 5 * scale val total = 5 * scale } java.lang.IllegalArgumentException: requirement failed at scala.Predef$.require(Predef.scala:207) at student_percent$class.$init$(<console>:11) ... 40 elided |
The exception in this example was thrown because total still had its default value of 0 when trait student_percent was initialized, which caused the require invocation to fail.
Pre-initialized fields
Pre-initialized fields allows to initialize the fields of a subclass before the superclass is called. The field definition is placed in the braces before the superclass constructor call. For example create trait student_percent as;
1 2 3 4 5 6 7 8 9 |
trait student_percent { val obtained: Int val total: Int require(total != 0) val perc = (obtained.toFloat / total.toFloat) * 100 override def toString = "Percentage secured is" + perc } |
Now call the trait student_percent by initializing values for “obtained” and “total” as
1 2 3 4 5 6 |
new { val obtained = 80 val total = 100 } with student_percent |
Output:res22: student_percent = Percentage secured is80.0
The fields can be initialized in object definition as;
1 2 3 4 5 6 |
object stud extends { val obtained = 70 val total = 100 } with student_percent |
Below image shows the above code execution in scala shell.
That’s all for abstract types in Scala programming, we will look into annotations in coming posts.