Can't invoke method in class' "this" method - scala

I'm running into
error: not found: value defineParser
[scalac-2.11] def this(format: String) = this(format, defineParser(format))
when I try to call a method in the this method of a class in order to dynamically return a parser depending on the format.
The class entire structure looks like so:
class TimestampConversion(format: String, parser: DSVTimestampFormatter) extends ObjectConversion[Any] with FormattedConversion[DSVTimestampFormatter] {
def defineParser(format: String): DSVTimestampFormatter = {
// hidden implementation details
}
def this(format: String) = this(format, defineParser(format))
}
And this fails on compiling this class. Why am I not able to invoke the defineParser method? It's well defined there.

It's OK to define a secondary constructor, but it's slightly more idiomatic to add apply factory methods to the companion object instead.
It's also possible to add a default arg for the parameter in the primary constructor, where it's more obvious what the scope is:
class C(format: String)(parser: Parser = C.defineParser(format))
object C { private def defineParser(format: String): Parser = ??? }
Here is the spec language (section 5.3.1) saying that the scope for your this invocation is not "inside the braces of the class definition":
The signature and the self constructor invocation of a constructor
definition are type-checked and evaluated in the scope which is in
effect at the point of the enclosing class definition, augmented by
any type parameters of the enclosing class and by any early
definitions of the enclosing template. The rest of the constructor
expression is type-checked and evaluated as a function body in the
current class.

Related

Scala: Which implicit parameter takes priority? The one declared where a method is defined? Or where the method is called?

If a method is defined in an object to take in an implicit parameter like this:
object MyApp {
implicit val implicitParameter: String = "Hello!"
def printImplicitString()(implicit ip: String): Unit = println(ip)
}
..and then this method is called in another object that that has its own implicit parameter of type String, which one gets precedence?
object MyOtherApp extends App {
implicit val implicitParamter2: String = "World!"
MyApp.printImplicitString()
}
Does this print Hello! or World!? Can't get it to run in intellij, probably because it may be invalid code.
The one near the method call will take priority. Scala will start from the scope where the method is called and work its way backwards. According to Scala Docs here and here:
First, eligible are all identifiers x that can be accessed at the point of the method call without a prefix and that denote an implicit definition or an implicit parameter.
Second, eligible are also all members of companion modules of the implicit parameter’s type that are labeled implicit
So this code will print 'World!'

Scala - Create user-type with method

I have a generic class which takes one type, and I have a parameter from that type. The issue is that I need to use a method from this parameter (in my problem, I need to use the method getTimestamp).
I can't have a trait or an abstract class because I know that, at some point, the type will be a Java Class that I can't modified.
I tried something like this :
type InputWithTimestamp = {def getTimestamp: Long}
class Foo[Input <: InputWithTimestamp](f : Input) {
def printTimestamp = { println(f.getTimestamp) }
}
class Test(timestamp : Long) {
def getTimestamp = timestamp
}
val t = new Test(1000)
val f = new Foo(t)
f.printTimestamp
And it is perfectly working.
But as I said, at some point I need to use a java class as a type.
And here is my problem :
Even if the java class defined a method getTimestamp which returns a long, I have the following error :
Error: inferred type arguments [MyJavaClass] do not conform to class Foo's type parameter bounds [Input <: InputWithTimestamp]
So what can I do to have a generic type which defined this method without needing to modify my java class ?
The problem in my case was that I didn't use parentheses to declare my method getTimestamp (because you get a warning in IDEA if you do so).
But in that case, I need the parentheses, otherwise the java method getTimestamp doesn't match the scala method
type InputWithTimestamp = {def getTimestamp: Long}
works perfectly.

Overriding the method of a generic trait in Scala

I defined a generic Environment trait:
trait Environment[T]
For which I provide this implementation:
class MyEnvironment extends Environment[Integer] {
val specific: Integer = 0
}
Furthermore, I defined a generic Event trait that has one method that accepts a generic Environment as parameter:
trait Event[T] {
def exec(e: Environment[T])
}
For this Event trait, I provided the following implementation, where the exec() method accepts a parameter of the type MyEnvironment, to enable me to access the specific value of MyEnvironment.
class MyEvent extends Event[Integer] {
override def exec(e: MyEnvironment): Unit = {
println(e.specific)
}
}
However, the Scala compilers outputs an error, from where it seems that
MyEnvironment is not recognized as an Environment[Integer]:
Error: method exec overrides nothing.
Note: the super classes of class MyEvent contain the following, non final members named exec: def exec(t: main.vub.lidibm.test.Environment[Integer]): Unit
Is it possible to make this work, or are there patterns to circumvent this problem.
You can't narrow down the signature of a method; it's not the same method any more. In your case, you can't override
def exec(e: Environment[T]): Unit
with
override def exec(e: MyEnvironment): Unit
Second method is more specific than the first one. It's conceptually the same as e.g. overriding def foo(a: Any) with def foo(s: String).
If you want it to work, you need to use the same type in both signatures (note that if you use an upper bound such as T <: Environment[_], that means that a method that accepts T actually accepts any subclass of Environment, so overriding using MyEnvironment will work OK in that case).
Because overriding is not polymorphic in the method's parameter types. It works the same way as in Java. In the example what you have done is overloaded the method in reality.That is they are treated as different methods.
For overriding the method names ie. the name , signature , types has to be the same.

Why does auxiliary constructor not see import done in the class?

The code below gives a compile error:
class Info(val x: String)
object Info {
val default = new Info("top")
}
case class Data(x: String) {
import Info.default
def this() = this(default.x)
}
Error:(11, 23) not found: value default
def this() = this(default.x)
Why is symbol default not seen in the constructor, in spite of the import?
Further experiments show it is not only import. Replacing import line with a def (or even val) does not help, still the error persists:
def default = Info.default
Scoping doesn't work the way you expected because of the scoping of self constructor invocations (when secondary constructors invoke the primary constructor):
The signature and the self constructor invocation of a constructor
definition are type-checked and evaluated in the scope which is in
effect at the point of the enclosing class definition, augmented by
any type parameters of the enclosing class and by any early
definitions of the enclosing template.
In other words, the scope in effect for the expression default.x is the scope outside Data.
This is confusing because textually it looks like that expression is inside the class.
This rule has to do with lexical scope and not with evaluation order.
You have to move the import outside the class definition.
For fun, scoping is slightly broken in the following case:
object Playroom {
def default = "playing"
case class Toy(squeezeMsg: String = default)
object Toy {
def default = "srsly"
}
}
object Test extends App {
import Playroom._
println(Toy())
println(new Toy())
}
which is this puzzler. Generally speaking, it's more idiomatic (and robust) to use apply methods on the companion.
This is behaving according to specs. The body of the class is part of the so called primary constructor. The auxiliary constructor(s) needs to start by calling the primary or another auxiliary defined before. Assuming you only have one auxiliary, since the call to primary must be the first statement in your auxiliary, it means that during this first statement you do not have access to anything defined inside the primary. After the first call is done, then you can access any of the members and imports defined in the primary.
In your example, the problem is that the import (import Info.default) is not visible to the first statement of your auxiliary. If you replace it with def this() = this(Info.default.x) it should work.
Example:
The following compiles fine since the call to Constant is done after the call to the primary.
class G(i: Int) {
val Constant = 1
// No argument auxiliary constructor
def this() = {
this(3) // Call to primary
println(Constant * 2)
}
}
The following does not compile since the call to Constant is done before the call to the primary, which means that Constant has not been created yet.
class G(i: Int) {
val Constant = 1
// No argument auxiliary constructor
def this() = {
this(Constant) // This will cause an error!
}
}
Solution:
Have any constants you need defined in the companion object. The companion object is by definition initialized first, so you will be able to access any members of it from within the constructors of your class.
object G {
val Constant = 1
}
class G(i: Int) {
// No argument auxiliary constructor
def this() = {
this(G.Constant) // This now works!
}
}
In scala, any fields defined in the class is not available until after the primary constructor is invoked. To fix it is usually used companion object with apply method.

Context bounds for type members or how to defer implicit resolution until member instantiation

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.