Scala inheritance with a abstract class - scala

I am new to scala, just doing some practice;
I tried a very simple program, briefed as following:
abstract class Device(val cds: Array[Char]) {
var codes = Array[Char](cds: _*)
def encrpt(code: Char): Char
var nextDevice: Device
def setNext(next: Device):Unit = {
nextDevice = next
}
}
//compiler error shows here
class Input(codes: Array[Char]) extends Device(codes) {
override def encrpt(code: Char) = code
}
you could see there is a compiler error at line 21, following is the message:
class Input needs to be abstract, since variable nextDevice in class Device of type com.me.acm.problem1009.Device is not
defined (Note that variables need to be initialized to be defined)
I am pretty confusing that error, my understanding, define some variable and an setter method in the parent class, so the child classes can use it without define it again. it is straight forward.
I guess I missed something. Could someone explain it to me and tell what is the correct way? thanks.

In Scala, variables do not have assumed default values as they do in Java (or many other languages). Thus, when you declare a variable, you must always specify its initial value.
In your code, you declare a variable nextDevice, but you do not give it a value. Since Scala always needs a value, it interprets what you've written as nextDevice being an abstract field, so the compiler is telling you that it must be overridden.
If you change that line to the following, for example, to specify an initial value, then the error will disappear:
var nextDevice: Device = new Input(Array())

As the error message is telling you, the variable nextDevice needs to be initialized in the constructor on Input.
class Input(codes: Array[Char]) extends Device(codes) {
override def encrpt(code: Char) = code
nextDevice = null
}
Note that using null is frowned upon in Scala. You should probably change the type of your variable to Option[Device]

Related

Getting Scala enum instances

I have the following Scala enum which I designed after reading this answer:
object RunMode extends Enumeration {
val CLIENT_MODE = Value("CLIENT_MODE")
val SERVER_MODE = Value("SERVER_MODE")
}
I am now trying to pass an instance of it as an argument into the constructor of another class:
package com.me.myapp.shared.config
import com.me.myapp.shared.utils.RunMode
class MyAppConfig(runMode : RunMode) {
}
This gives me a compiler error:
Cannot resolve symbol RunMode
BTW: com.me.myapp.shared.utils.RunMode is the correct package path for RunMode, so that's not the issue here!
I assume that this is maybe because there is only (ever) one single instance of the RunMode object, and perhaps that prevents it from being passed in as an arg.
Either way, I don't really care what the solution is. But I need an "enum" called RunMode and I'll need to be able to pass instances of it into contructors of other classes. Any ideas?
You are almost there, the correct type for a value of an Enumeration is Enumeration.Value, so here you need to use:
class MyAppConfig(runMode : RunMode.Value) {
}
You're correct in the assumption that the only instance that inhabits the type RunMode is the object itself.
However fixing your problem isn't all that difficult.
object RunMode extends Enumeration {
type RunMode = Value
val CLIENT_MODE = Value("CLIENT_MODE")
val SERVER_MODE = Value("SERVER_MODE")
}
The Enumeration class gives you the type Value which is the type that all of your enumerated types should have. It's scoped to the class instance, so every instance of Enumeration get's its own Value type.
You can give it a proper name by creating a type alias.
Then you can import the inner type alias like this:
import com.me.myapp.shared.utils.RunMode._
And then you can pass Instances of your Enumeration around, therefore also allowing you to keep the MyAppConfig the same as it is right now.
Alternatively, you could of course also omit the type alias and just change the type signature of MyAppConfig to RunMode.Value. However I believe the former method is much better at clarifying intent.
class MyAppConfig(runMode: RunMode.Value) {
}

Scala, why do I not need to import deduced types

I feel like I should preface this with the fact that I'm building my projects with sbt.
My problem is that, if at compile time a method returns something of an unimported type, in the file where I call the method, as long as I use type inference, everything compiles. Once I try to assign the unimported type to the var/val which I created with the return value of my function, I get a compiler error.
Lets say I have two classes in two package. Class App in package main and class Imported in package libraries. Lets further more say that we have a class ImportedFactory in the package main and that this class has a method for creating objects of the type Imported.
This code compiles just fine:
class App() {
// method return object of type Imported
val imp = ImportedFactory.createImportedObject()
}
This doesn't:
class App() {
// method return object of type Imported
val imp : Imported = ImportedFactory.createImportedObject()
}
This yet again does:
import libraries.Imported
class App() {
// method return object of type Imported
val imp : Imported = ImportedFactory.createImportedObject()
}
This seems like rather strange behavior. Is this normal for languages with type inference at compile time and I've yet to notice it until now in go/C++ due to my ignorance ?
Does one of the two valid approaches (import&explicit type vs infered) have advantages/drawback over the other ? (expect for, of course, one being more explicit and verbose and the other one being shorter)
Is this black magic or does the Scala compiler accomplish these deductions in a rather straight forward way ?
The only thing importing does is making a not fully qualified name available in the current scope. You could just as well write this:
class App() {
val imp: libraries.Imported = ImportedFactory.createImportedObject()
}
The reason you import libraries.Imported is for making the shorter name Imported available for you to write. If you let the compiler infer the type, you don't mention the type in your code, so you don't have to import its shorter name.
And by the way: this has nothing to do with dynamic casting in C++. The only mechanism at work in your code is type inference.
note: You'll get better search results with the term type inference
With val imp = ImportedFactory.createImportedObject() you are letting the compiler figure out what type imp should be based on type inference. Whatever type createImportObject returns, that's what type imp is.
With val imp : Imported = ImportedFactory.createImportedObject() you are explicitly stating that imp is an Imported. But the compiler doesn't know what you mean by that unless you... import... it.
Both approaches have merit:
inferred types
Inferred types are great for when you're throwing together code where the type should be obvious:
val i = 1 // obviously `i` is an int
val j = i + 10 // obviously still an int
It's also great for local vars/vals where the type would be too much of a pain to write
val myFoo: FancyAbstractThing[TypeParam, AnotherTypeParam[OhNoMoreTypeParams]] = ...
// vs
val myFoo = FancyThingFactory.makeANewOne()
The downside is that if you have allowed a public def/val to have an inferred type, it can be more difficult to determine how to use that method. For this reason, omitting type annotations is typically only used for simple constants, and in local vals/vars that "client code" doesn't have to look at.
explicit types
When you do want to write library-ish code (i.e. public vals/defs), the convention is to explicitly-type them.
Probably the simplest reason for this is because this:
def myLibraryMethod = {
// super complicated implementation
}
is harder to understand than
def myLibraryMethod: String = {
// super complicated implementation
}
Another benefit to explicitly-typing your code is when you want to expose a less-specific type than what the value actually is:
val invalidNumbers: Set[Int] = TreeSet(4, 8, 15, 16, 23, 42)
In this example, you don't want client code to need to care that your invalidNumbers is actually a TreeSet. That's an implementation detail. In this case you're hiding some information that, while true, would be distracting.

Scala: getting rid of type argument in a function

Suppose I have a function defined in the following way:
def fun[T](somevar: SomeType[T]) = {
// some action
}
Is there a way to git rid of type parameter [T] and just use it as
def fun(somevar: SomeType[T]) = {
// some action
}
I mean, the type information should already be available inside someVar, no? Why not use them somehow?
The purpose of your question is unclear.
The users of your function (the client code) don't need to worry about the type parameter. They can just call fun(myvar).
If the type T is immaterial to the body of fun() then it can be dropped: SomeType[_]
But if T is meaningful to the workings of the function then the compiler has to be told that it is a type parameter. Just seeing this, SomeType[T], the compiler can't infer that T is now a type parameter. It will, instead, look for a definition of T outside of fun() and, not finding it, will throw an error.
This would be problematic because what you're removing was never actually redundant. When the function is defined as def fun[T](...), T is defined as a new type variable. Otherwise, it refers to a type or type variable defined somewhere else. You seem to think that
def fun(somevar: SomeType[T]) { ... }
should mean that T is a new type variable. Is that always the case, though? Not in this code:
trait T { ... }
def fun(somevar: SomeType[T]) { ... }
So where do we go from there? Define new type variables whenever a type name is referred to that hasn't been defined before? That would turn the following compile-time errors truly weird. (Or worse, sometimes allow them to compile?)
def fun(somevar: SomeType[Integr]) { ... }
class C[Thing] {
def g(x: List[Think]) = ...
}
For the compile-time type-checking philosophy of Scala, that way lies madness.
Unless you want T to be a specific type, no, there is not. The method signature wouldn't be valid without it. What somevar knows is irrelevant.
You can't do this. Compiler needs to know what is type T. If you don't care about SomeType type parameter, you can use this form:
def fun(somevar: SomeType[_]) = {
// some action
}

Declare a null var in Scala

I have read that null should not be used in scala.
How can I leave myVar uninitialized without the use of null?
class TestClass {
private var myVar: MyClass = null
}
I understand I can just make a dummy MyClass, that is never used in place of the null. But this can and does reduce the code's understandability.
As Rado has explained I can change null as shown below. I understand that I can now check to see if the variable is set during run-time, however, if I don't program that check then there is no benefit of using Option in this case.
Coming from Java, I feel there should be a way to simply leave the var uninitialized at compile-time and let it set during run-time without using the Option class, because as I mentioned above, if I don't code for the unset case then why use Option?
class TestClass {
private var myVar: Option[MyClass] = None
private def createVar() {
myVar = Some(new MyClass)
x: MyClass = myVar.get
}
}
I am thinking the only other way of doing what I am asking is:
class TestClass {
// Using dummy MyClass that will never be used.
private var myVar: MyClass = new MyClass
private def process(myVar: MyClass) {
this.myVar = myVar
myVar.useVarMethod()
}
}
The Scala way is to declare the variable as Option[MyClass]:
class TestClass {
private var myVar: Option[MyClass] = None
private def createVar() {
myVar = Some(new MyClass)
}
// Usage example:
def useMyVar(): Unit = {
myVar match {
case Some(myClass) => {
// Use myClass here ...
println(myClass.toString)
}
case None => // What to do if myVar is undefined?
}
}
}
That way you avoid NullPointerException. You make it explicit that the variable can be in undefined state. Everytime you use the myVar you have to define what to do if it is undefined.
http://www.scala-lang.org/api/current/index.html#scala.Option
I need myVar to be of type MyClass not Option[MyClass]. I see that I
could use Rado's updated answer and then use the get method, but is
there any other way?
When you use Option you can telling the compiler and everyone else who will read/use your code that it's okay not to define this value and the code will handle that condition and not fail at runtime.
The other way of dealing with is to do null checks every time before you access the variable because it could be null and therefore throw an exception at runtime.
When you use Option, the compiler will tell you if at compile time that you have not handled a condition where the value of a variable maybe undefined.
If you think about it, it's really a big deal. you have converted a runtime exception (which is deterministic) to a compile-time error.
If you want to extract the value out of something like an Option (which supports map and also flatMap), then you don't necessarily have to keep doing pattern matching on whether or not the Option contains a value (i.e. is a "Some") or not (i.e. is a "None").
Two methods are very useful - if you want just alter (or "map") the value within the Option then you can use the map method, which takes a function with a general type of:
f: A => B
so in your case at compile time would end up being:
f: MyClass => B
When you map an option, if the option is a "Some" then the contained value is passed through to the mapping function, and the function is applied (to change the MyClass to a B if you like...) and the result is passed back wrapped in an Option. If your Option is a None, then you just get a None back.
Here's a simple example:
scala> case class MyClass(value : String)
defined class MyClass
scala> val emptyOption : Option[MyClass] = None
emptyOption: Option[MyClass] = None
scala> val nonEmptyOption = Some(new MyClass("Some value"))
nonEmptyOption: Option[MyClass] = Some(MyClass(Some value)
Try and extract the value from both option instances using map:
scala> nonEmptyOption map { s => s.value + " mapped" }
res10: Option[String] = Some(Some value mapped)
scala> emptyOption map { s => s.value }
res11: Option[String] = None
So basically, if you map across an empty option, you always get a None. Map across a non-empty Option and you can extract the contained value and transform it and get the result wrapped back in an Option. Notice that you don't need to explicitly check any patterns...the map method takes care of it.
Flatmap is a bit more challenging to explain, but it basically isn't massively different except that it takes a function which has type:
g: A => M[B]
which basically allows you to take the value out of the Option (the 'A' in the type signature above), do something to it (i.e. a computation) and then return the result ('B') - wrapped in another container such as another Option, List...
The same notion (across Option anyway) that if the Option is a None then nothing really happens still applies. flatMap and map form the basis of Scala "for comprehensions" which you can read about (and are done far more justice than I could!!) in lots of other places.

Verifying mocked object method calls with default arguments

Suppose I have this class:
class Defaults {
def doSomething(regular: String, default: Option[String] = None) = {
println(s"Doing something: $regular, $default")
}
}
I want to check that some other class invokes doSomething() method on Defaults instance without passing second argument:
defaults.doSomething("abcd") // second argument is None implicitly
However, mocking Defaults class does not work correctly. Because default values for method arguments are compiled as hidden methods in the same class, mock[Defaults] returns an object in which these hidden methods return null instead of None, so this test fails:
class Test extends FreeSpec with ShouldMatchers with MockitoSugar {
"Defaults" - {
"should be called with default argument" in {
val d = mock[Defaults]
d.doSomething("abcd")
verify(d).doSomething("abcd", None)
}
}
}
The error:
Argument(s) are different! Wanted:
defaults.doSomething("abcd", None);
-> at defaults.Test$$anonfun$1$$anonfun$apply$mcV$sp$1.apply$mcV$sp(Test.scala:14)
Actual invocation has different arguments:
defaults.doSomething("abcd", null);
-> at defaults.Test$$anonfun$1$$anonfun$apply$mcV$sp$1.apply$mcV$sp(Test.scala:12)
The reason of this is clear, but is there a sensible workaround? The only one I see is to use spy() instead of mock(), but my mocked class contains a lot of methods which I will have to mock explicitly in this case, and I don't want it.
This is related with how the Scala compiler implements this as a Java class, remember that Scala runs on the JVM, so everything needs to be transformed to something that looks like Java
In this particular case, what the compiler does is to create a series of hidden methods which will be called something like methodName$default$number where number is the position of the argument this method is representing, then, the compiler will check every time we call this method and if we don’t provide a value for such parameter, it will insert a call to the $default$ method in its place, an example of the “compiled” version would be something like this (note that this is not exactly what the compiler does, but it works for educational purposes)
class Foo {
def bar(noDefault: String, default: String = "default value"): String
}
val aMock = mock[Foo]
aMock.bar("I'm not gonna pass the second argument")
The last line would be compiled as
aMock.bar("I'm not gonna pass the second argument", aMock.bar$default$1)
Now, because we are making the call to bar$default$1 on a mock, and the default behaviour of Mockito is to return null for anything that hasn’t been stubbed, then what ends up executing is something like
aMock.iHaveSomeDefaultArguments("I'm not gonna pass the second argument", null)
Which is exactly what the error is telling…
In order to solve this some changes have to be made so mockito actually calls the real $default$ methods and so the replacement is done correctly
This work has been done in mockito-scala, so by migrating to that library you'll get a solution for this and many other problems that can be found when mockito is used in Scala
Disclaimer: I'm a developer of mockito-scala