I'm kinda new to scala. I got into trouble while trying to return object type.
Here is the code.
It shows "error: not found: type A"
object A{}
object B {
def getInstance() : A = {
return A
}
}
If I do similar kind of thing with class instance, it wont show any problem.
class A{}
object B {
def getInstance() : A = {
return new A
}
}
As far as I know object type is a singleton instance of class. What am I missing here?
Compiler complains that can not find type A because in your case A is a name of an object not a type, use A.type to refer to type, like this:
object A
object B {
def getInstance: A.type = A
}
Because object is a singleton is does not define a type, instead in defines a value.
If you would look at the Java equivalent, using scala object produces the:
A$ class //
A$.MODULE$ // singleton instance definition
The type is however masked and can be accessed via A.type.
Using return is also not necessary in Scala. The last statement position in a block is automatically interpreted as return value.
class A{}
object B {
def getInstance() : A = new A
}
Related
I know that, during runtime type parameters will be erased and hence we cannot access it directly. That's why there are reified type parameters in kotlin. But its usage is restricted only for functions. I even tried receiving explicit argument in constructor like this:
class Outer<T> {
inner class Inner(private val clazz: Class<T>) {
private fun func() {
if (obj is clazz) { // even tried obj is clazz::class.java
...
} else {
...
}
}
}
}
But this gives me Unresolved reference: clazz error in android studio. Someone please help me.
You can use the dynamic equivalent of is, which is Class.isInstance():
if (clazz.isInstance(obj)) { // ...
(KClass has an isInstance() method too, if you want to stick to pure Kotlin.)
clazz is not a class name, so you can't use is with it. It is a property with a type of Class<T>. So you have to use == to compare with it.
if (obj::class.java == clazz) { // ...
I have following two classes.
class A (name: String) {
}
object A {
}
According to definition of Singleton, we can have only one object of that type. However I am able to create two different objects of type A using following piece of code.
object B {
def main(args: Array[String]): Unit = {
val a = new A("Vinod")
println(a)
val b = new A("XYZ")
println(b)
}
}
can someone please explain me, where my understanding is not correct?
An object by itself is a singleton. It has its own class and no other instance of the same class exist at runtime.
However, the pattern you describe here is different: object A is not an instance of class A unless you make it so using object A extends A. You could make it the only instance of class A by making class A a sealed class, but this is unnecessary in almost all cases.
If you really want the singleton pattern, drop the class and use only object A, all of its members will be "static" in the sense of Java.
Note that the actual type of object A can be referred to as A.type, which by default is completely unrelated to type A if class A exists. Again, A.type could be a subtype of A if you explicitly make it so.
The companion object is not an instance of the companion class. They're not even the same type.
class A
object A {
var state = 0
def update() :Unit = state = state + 1
}
val abc :A = new A //instance of class A
val xyz :A.type = A //2nd reference to object A
// both reference the same singleton object
xyz.update() //res0: Unit = ()
A.state //res1: Int = 1
abc.state //Error: value state is not a member of A$A2521.this.A
the companion object can be thought of as the static space of a class. if you want to make A a singleton you can make it an object rather than a class
new A refers to class A (which is not a singleton), not to object A. You can easily check it: if you remove class A, the new A lines will no longer compile.
Also note that objects aren't necessarily singletons: they can be nested inside classes or traits, in this case there is one for each instance of the outer type.
I want to have a collection of objects, each object a companion of a different class, which classes all share a common method defined in a superclass that can be invoked when looping through the collection with a foreach(). I want the constructors of these sibling-classes to have the same named parameters and default parameter values as each other. Finally, I want to minimize repeated code.
Thus far, I am trying to do this with case classes, since--if it worked--it would eliminate all the duplicated code of the companion-objects for each type. The problem is that if I put all these companion objects into a Set, when I take them out again I lose the default parameters and parameter names.
Here is some example code of what I am describing:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
case class caseOne(override val param: String = "default") extends MyType
case class caseTwo(override val param: String = "default") extends MyType
object Main extends App {
// I can construct instances using the companion objects' `apply()` method:
val works1 = caseOne(param = "I have been explicitly set").label
// I can construct instances that have the default parameter value
val works2 = caseOne().label
// But what I want to do is something like this:
val set = Set(caseOne, caseTwo)
for {
companion <- set
} {
val fail1 = companion() // Fails to compile--not enough arguments
val fail2 = companion(param = "not default") // Fails also as param has lost its name
val succeeds = companion("nameless param") // this works but not what I want
println(fail1.label + fail2.label) // this line is my goal
}
}
Notably if the Set has only one element, then it compiles, suggesting the inferred type of the multi-element Set lacks the parameter name--even though they are the same--and the default values. Also suggesting that if I gave the Set the right type parameter this could work. But what would that type be? Not MyType since that is the type of the companion classes rather that the objects in the Set.
I could define the companion objects explicitly, but that is the repeated code I want to avoid.
How can I loop through my collection, constructing instances of MyType subclasses on each iteration, with constructors that have my desired parameter names and default values? All while minimizing repeated code?
Update: Originally the example code showed caseOne and caseTwo as having different default values for param. That was incorrect; they are now the same.
You're not going to be able to get exactly what you want since you don't really have much control over the auto-generated companion objects. In particular for this to work they would all need to extend a common trait. This is why it fails to compile when the set has more than one companion object; even though they all have a method with the same signature, they don't extend a common trait for the compiler to utilize.
You can use a nested case class and get something very similar though:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
abstract class MyTypeHelper(default: String) {
case class Case(param: String) extends MyType
def apply(param: String) : Case = Case(param)
def apply(): Case = apply(default)
}
object One extends MyTypeHelper("default one")
object Two extends MyTypeHelper("default two")
object Example {
val works1 = One(param = "I have been explicitly set").label
val works2 = One().label
val set = Set(One, Two)
for {
companion <- set
} {
val a = companion()
val b = companion(param = "not default")
val c = companion("nameless param")
println(a.label + b.label)
}
}
Instead of having a caseOne type, you have One.Case, but it still implements MyType so you shouldn't have any issue anywhere else in the code that uses that trait.
In scala, the shit can hit the fan if the caller of a generic method omits to explicitly specify the type parameter. For example:
class Expression[+T] // Will have eval():T method, so +T
class NothingTest {
def makey[T](): Expression[T] = null
def needsBool(b: Expression[Boolean]): Unit = {}
var b: Expression[Boolean] = null
var n = makey() // : Expression[Nothing]
b=n // Yikes.
needsBool(n) // :-/ Supplied Expression[Nothing] ... not a Expression[Nothing]
}
I'm supposed to supply a type parameter to makey() (e.g. makey[Boolean]() ), however in this instance I forgot, the program compiled (which, by the way, is extremely easy to do).
The program will eventually fail in needsBool (implementation omitted) which did not receive an Expression[Booolean] object - it got an Expression[Nothing] object instead. Scala's docs says Nothing is a subclass of all types, which seems exceptionally rude and is certain to break type safety wherever it appears.
So, to reintroduce some type-safety, can I either:
prevent makey from returning Expression[Nothing] but requiring that a type parameter be provided? (I suspect not), OR
prevent needsBool from receiving an Expression[Nothing]?
at compile-time.
Update:
A fuller (compiling, but runtime failing example):
class Expression[+T](val value:T){
def eval:T = value
}
class NothingTest {
def makey[T](): Expression[T] = new Expression[String]("blah").asInstanceOf[Expression[T]]
def needsBool(b: Expression[Boolean]): Unit = {
val boolval = b.eval // Explode! String is not a Boolean
println(boolval)
}
var b: Expression[Boolean] = null
var n = makey() // : Expression[Nothing]. You're suppose to supply a type, but forgot.
b=n // Yikes.
needsBool(n) // :-/ Supplied Expression[Nothing]
}
I've found a somewhat hacky solution, but it works.
Create a NotNothing type that's contravariant in its type parameter, then provide an implicit object for both Any and Nothing.
Now if you try to use a value of NotNothing with Nothing the compiler will complain about ambiguity. Case in point:
sealed trait NotNothing[-T]
object NotNothing {
implicit object YoureSupposedToSupplyAType extends NotNothing[Nothing]
implicit object notNothing extends NotNothing[Any]
}
Then constrain your makey function with the NotNothing type:
def makey[T : NotNothing]() = { ... }
And voila now you'll get a compile time error if you forget to supply a type!
In the following example, is there a way to avoid that implicit resolution picks the defaultInstance and uses the intInstance instead? More background after the code:
// the following part is an external fixed API
trait TypeCls[A] {
def foo: String
}
object TypeCls {
def foo[A](implicit x: TypeCls[A]) = x.foo
implicit def defaultInstance[A]: TypeCls[A] = new TypeCls[A] {
def foo = "default"
}
implicit val intInstance: TypeCls[Int] = new TypeCls[Int] {
def foo = "integer"
}
}
trait FooM {
type A
def foo: String = implicitly[TypeCls[A]].foo
}
// end of external fixed API
class FooP[A:TypeCls] { // with type params, we can use context bound
def foo: String = implicitly[TypeCls[A]].foo
}
class MyFooP extends FooP[Int]
class MyFooM extends FooM { type A = Int }
object Main extends App {
println(s"With type parameter: ${(new MyFooP).foo}")
println(s"With type member: ${(new MyFooM).foo}")
}
Actual output:
With type parameter: integer
With type member: default
Desired output:
With type parameter: integer
With type member: integer
I am working with a third-party library that uses the above scheme to provide "default" instances for the type class TypeCls. I think the above code is a minimal example that demonstrates my problem.
Users are supposed to mix in the FooM trait and instantiate the abstract type member A. The problem is that due to the defaultInstance the call of (new MyFooM).foo does not resolve the specialized intInstance and instead commits to defaultInstance which is not what I want.
I added an alternative version using type parameters, called FooP (P = Parameter, M = Member) which avoids to resolve the defaultInstance by using a context bound on the type parameter.
Is there an equivalent way to do this with type members?
EDIT: I have an error in my simplification, actually the foo is not a def but a val, so it is not possible to add an implicit parameter. So no of the current answers are applicable.
trait FooM {
type A
val foo: String = implicitly[TypeCls[A]].foo
}
// end of external fixed API
class FooP[A:TypeCls] { // with type params, we can use context bound
val foo: String = implicitly[TypeCls[A]].foo
}
The simplest solution in this specific case is have foo itself require an implicit instance of TypeCls[A].
The only downside is that it will be passed on every call to foo as opposed to just when instantiating
FooM. So you'll have to make sure they are in scope on every call to foo. Though as long as the TypeCls instances are in the companion object, you won't have anything special to do.
trait FooM {
type A
def foo(implicit e: TypeCls[A]): String = e.foo
}
UPDATE: In my above answer I managed to miss the fact that FooM cannot be modified. In addition the latest edit to the question mentions that FooM.foo is actually a val and not a def.
Well the bad news is that the API you're using is simply broken. There is no way FooM.foo wille ever return anything useful (it will always resolve TypeCls[A] to TypeCls.defaultInstance regardless of the actual value of A). The only way out is to override foo in a derived class where the actual value of A is known, in order to be able to use the proper instance of TypeCls. Fortunately, this idea can be combined with your original workaround of using a class with a context bound (FooP in your case):
class FooMEx[T:TypeCls] extends FooM {
type A = T
override val foo: String = implicitly[TypeCls[A]].foo
}
Now instead of having your classes extend FooM directly, have them extend FooMEx:
class MyFoo extends FooMEx[Int]
The only difference between FooMEx and your original FooP class is that FooMEx does extend FooM, so MyFoo is a proper instance of FooM and can thus be used with the fixed API.
Can you copy the code from the third party library. Overriding the method does the trick.
class MyFooM extends FooM { type A = Int
override def foo: String = implicitly[TypeCls[A]].foo}
It is a hack, but I doubt there is anything better.
I do not know why this works the way it does. It must be some order in which the type alias are substituted in the implicitly expression.
Only an expert in the language specification can tell you the exact reason.