scala assignment operator _= not working in trait - scala

Here is the code:
trait MacApp {
def dockerIcon_=(s: String) = println("setting docker icon...")
}
object Main extends App with MacApp {
dockerIcon = "apple"
}
The scalac complains this:
Main.scala:6: error: not found: value dockerIcon
dockerIcon = "apple"
^
one error found
I see scala-swing library use _= a lot, e.g., https://github.com/scala/scala-swing/blob/2.0.x/src/main/scala/scala/swing/Label.scala#L28
Thanks!

You need both getter and setter:
scala> :pa
// Entering paste mode (ctrl-D to finish)
trait MacApp {
def dockerIcon_=(s: String) = println("setting docker icon...")
def dockerIcon = 42
}
object Main extends App with MacApp {
dockerIcon = "apple"
}
// Exiting paste mode, now interpreting.
defined trait MacApp
defined object Main
scala> Main main null
setting docker icon...
http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#assignments
Your expectations about the pair of members are established earlier at:
http://www.scala-lang.org/files/archive/spec/2.11/04-basic-declarations-and-definitions.html#variable-declarations-and-definitions

You're trying to assign to a function? I don't think that _= Swing code is using an operator, I think it's just an odd name...possibly for some obscure Java compatibility reason that escapes me at the moment.
But def defines a function, not a value, so you can't assign to it; you have to call it. Check out this console fragment:
scala> def text_=(s: String) = s + "foo"
text_$eq: (s: String)String
scala> text_=("bar")
res3: String = barfoo

Related

How to Map with a case class in Scala

I am trying to convert, a Map with the case class I defined using the Apply.
case class ETLConfig (srcTableName:Option[String] = None,
idCol:Option[String] = None ,
orderingCol:Option[String] = None)
object ETLConfig {
def apply(map: Map[String, String]): ETLConfig =
ETLConfig(map.get("srcTableName"),map.get("idCol"),map.get("orderCol"))
}
Error:
command-512604125416347:2: error: too many arguments for method apply: (map: Map[String,String])ETLConfig in object ETLConfig
def apply(map: Map[String, String]):ETLConfig = ETLConfig(map.get("srcTableName"),map.get("idCol"),map.get("orderCol"))
Can someone please point me the whats wrong I am doing.
Also I tried the below and is working.
val empMap:Map[String, String] = Map("srcTableName" -> "Employee","idCol" -> "EmpId", "orderCol" -> "CreatedOn" )
val empConfig = ETLConfig(dtMap.get("srcTableName"),dtMap.get("idCol"), dtMap.get("orderCol"))
val srcTable = dtConfig.srcTableName.orNull
EDIT: Since you're using Databricks, you should define your classes and objects in package cells.
Original Answer:
I assume you're doing this in a REPL. A case class and its companion object need to be in the same file. In the usual Scala REPL, each command counts as a new "file." This means that your ETLConfig object is not a companion to your case class, with the result that it shadows your apply method instead of overloading it (and you can't call the original one as a result).
In the official Scala REPL, you can solve this by using the :paste command:
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class ETLConfig (srcTableName:Option[String] = None,
idCol:Option[String] = None ,
orderingCol:Option[String] = None)
object ETLConfig {
def apply(map: Map[String, String]): ETLConfig =
ETLConfig(map.get("srcTableName"),map.get("idCol"),map.get("orderCol"))
}
// Exiting paste mode, now interpreting.
defined class ETLConfig
defined object ETLConfig
From your output, it looks like you're using a different REPL, so I don't know if this will work.

Pimp my library on Joda LocalDate does not work

Here I am adding a new method to to LocalDate:
object EnhancedDate {
implicit class EnhancedDate(start: org.joda.time.LocalDate) {
/** Generates dates between start and end - inclusive */
def to(end: org.joda.time.LocalDate): IndexedSeq[org.joda.time.LocalDate] = {
val numberOfDays = Days.daysBetween(start, end.plusDays(1)).getDays()
for (f <- 0 to numberOfDays) yield start.plusDays(f)
}
}
}
and now using it:
import cats.effect.IO
import EnhancedDate.EnhancedDate
def loadCadUsdRates: IO[Map[String, CadInUsd]] = IO {
val start = new org.joda.time.LocalDate(startYear,1,1)
val end = new org.joda.time.LocalDate(endYear+1,1,1).minusDays(1)
start to end map(f) toMap
}
Function f doesn't really matter; you can use identity for all it's worth bc the results are the same.
I use Idea and everything is fine in the IDE (no red underlyings) but when I run it I get this error:
Error:(104, 9) value to is not a member of org.joda.time.LocalDate
start to end map(f) toMap
Now I've used pimp my library before and I'm pretty sure this is the right way to do it, but there must be something about joda date that is incompatible with it... Have you tried pimping Joda LocalDate.. I do not know why this is not working
I'm not exactly sure what is going on here but it's something to do with the declaration being a module with the same name as the implicit class within it. This means that you have two identifiers in scope, both called EnhancedDate and I assume that this must cause resolution ambiguity. It's certainly nothing to do with Joda. One definite workaround is to place your implicit class inside the nearest package object.
package object myPackage {
implicit class EnhancedDate(start: org.joda.time.LocalDate) { ... }
}
Here's a demonstration of it not working:
scala> :paste
// Entering paste mode (ctrl-D to finish)
object Foo {
implicit class Foo(s: String) { def foo = println(s"Foo: $s") }
}
// Exiting paste mode, now interpreting.
defined object Foo
scala> import Foo._
import Foo._
scala> "hey".foo
<console>:14: error: value foo is not a member of String
"hey".foo
^
Here is it working:
scala> object Bar {
| implicit class Foo(s: String) { def foo = println(s"Foo: $s") }
| }
defined object Bar
scala> import Bar._
import Bar._
scala> "hey".foo
Foo: hey

Scala: How can an import prevent finding an implicit value?

I could use suggestions debugging an implicit:
I want to use the implicit, x:
type T
trait HasT {
implicit def x: T = ...
}
But I also need a wildcard import from some package foo. I've tried two different ways of introducing both:
class UseT extends HasT {
import foo._
implicitly[T] // fails! "could not find implicit value"
// use foo stuff
}
and
class UseT {
object hasT extends HasT
import hasT.x
import foo._
implicitly[T] // fails! "could not find implicit value"
}
Both fail with "could not find" (not "ambiguous implicits values").
This happens while implicit identifier x: T is accessible at the point of method call via either inheritance or importing.
My workaround is to rebind x to an implicit val before the import. Both of the following work:
implicit val x2: T = implicitly[T]
import foo._
implicitly[T] // works!
and
implicit val x2: T = x
import foo._
implicitly[T] // works!
What value could possibly be in foo to cause this behavior?
My first guess is that there is some competing implicit in foo, but if it were higher priority, the following implicitly would still work, and if it were an ambiguous implicit, I'd be getting a different a different error.
edit: Miles Sabin's guess was correct! I found the shadowing implicit: timeColumnType. I still don't completely understand how this works given Som Snytt's observation that the shadowing implicit was wildcard imported (lower priority) while the shadowed was inherited (part of highest priority), so I'll leave the whole post here for posterity.
retracted: A second guess, offered by miles sabin, is implicit shadowing. I've since clarified my post to exclude that possibility. That case would be consistent with my errors if I had tried package hasT extends HasT; import hasT._, but As som-snytt points out, those two cases would not result in shadowing.
In my specific case, this can be confirmed by changing the name of the implicit I'm trying to use.
(This is false. I likely missed a publishLocal or reload while using this test to verify.)
context: I'm actually trying to use slick. The implicit T above is actually a column type mapping:
import slick.driver.JdbcProfile
class Custom { ... } // stored as `Long` in postgres
trait ColumnTypes {
val profile: JdbcProfile
import profile.api._ // this is `foo` above
type T = profile.BaseColumnType[Custom]
implicit def customColumnType: T =
MappedColumnType.base[Custom, Long](_.toLong, Custom.fromLong)
}
class DatabaseSchema(val profile: JdbcProfile) extends ColumnTypes {
// `implicitly[T]` does not fail here.
import profile.api._ // this is also `foo` above
// `implicitly[T]` fails here, but it's needed for the following:
class CustomTable(tag: Tag) extends Table[Custom](tag, "CUSTOMS") {
// following fails unless I rebind customColumnType to a local implicit
def custom = column[Custom]("CUSTOM")
def * = custom
}
}
The type of api/foo is JdbcProfile.API. The offending implicit is probably here, but I can't tell why. I'll try blocking some of those from being imported and see if I can narrow it down.
I think it's most likely that foo contains a definition named x. When (wildcard) imported from foo it shadows the local definition,
scala> object foo { val x: Boolean = true }
defined object foo
scala> implicit val x: Int = 23
x: Int = 23
scala> implicitly[Int]
res0: Int = 23
scala> import foo._
import foo._
scala> implicitly[Int]
<console>:17: error: could not find implicit value for parameter e: Int
implicitly[Int]
^
This is clearly a bug in implicit search.
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. An eligible identifier may thus
be a local name, or a member of an enclosing template, or it may be
have been made accessible without a prefix through an import clause.
In the example, unprefixed x refers to the inherited symbol. X.x is not accessible without a prefix.
Implicit search is fumbling the import.
$ scala
Welcome to Scala 2.12.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.
scala> :pa
// Entering paste mode (ctrl-D to finish)
object X { def x: Int = 42 }
trait T { def x: Int = 17 }
object Y extends T {
import X._
def f = x
}
// Exiting paste mode, now interpreting.
defined object X
defined trait T
defined object Y
scala> Y.f
res0: Int = 17
scala> :pa
// Entering paste mode (ctrl-D to finish)
object X { implicit def x: Int = 42 }
trait T { implicit def x: Int = 17 }
object Y extends T {
import X._
def f: Int = implicitly[Int]
}
// Exiting paste mode, now interpreting.
<pastie>:19: error: could not find implicit value for parameter e: Int
def f: Int = implicitly[Int]
^
scala> :pa
// Entering paste mode (ctrl-D to finish)
object X { implicit def x: Int = 42 }
trait T { implicit def x: Int = 17 }
object Y extends T {
import X.{x => _, _} // avoids bug, but is redundant
def f: Int = implicitly[Int]
}
// Exiting paste mode, now interpreting.
defined object X
defined trait T
defined object Y
scala>
The other example using the REPL is scoped this way:
scala> :pa
// Entering paste mode (ctrl-D to finish)
object X { def x: Int = 42 }
object Y { implicit def x: Int = 17 }
object Z {
import Y.x
def f = {
import X._
x
}
}
// Exiting paste mode, now interpreting.
<pastie>:19: error: reference to x is ambiguous;
it is imported twice in the same scope by
import X._
and import Y.x
x
^
Where x is not available at all, and the implicit is correctly excluded.
Just to confirm:
$ scala -Xlog-implicits
Welcome to Scala 2.12.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.
scala> :pa
// Entering paste mode (ctrl-D to finish)
object X { implicit def x: Int = 42 }
trait T { implicit def x: Int = 17 }
object Y extends T {
import X._
def f: Int = implicitly[Int]
}
// Exiting paste mode, now interpreting.
<console>:17: x is not a valid implicit value for Int because:
candidate implicit method x in object X is shadowed by method x in trait T
def f: Int = implicitly[Int]
^
<console>:17: x is not a valid implicit value for Int because:
candidate implicit method x in object X is shadowed by method x in trait T
def f: Int = implicitly[Int]
^
<console>:17: error: could not find implicit value for parameter e: Int
def f: Int = implicitly[Int]
^
scala>
Probably https://issues.scala-lang.org/browse/SI-9208

How to override = operator in Scala

Is there any way to override or overload = operator inside a class in Scala to implicitly converting data without defining implicit methods?
for example :
class A{
def =(str:String)={
.........
}
}
.........
val a=new A
a="TEST"
You can't override = in Scala because it is a language defined operator (like (, [ or <- are).
The only thing you can do is to use the update-method:
scala> :paste
// Entering paste mode (ctrl-D to finish)
class A {
var data = Map.empty[Int, String]
def update(i: Int, str: String) {
data += i -> str
}
def apply(i: Int): String =
data(i)
}
// Exiting paste mode, now interpreting.
defined class A
scala> val a = new A
a: A = A#77cb05b9
scala> a(5) = "hello"
scala> a(5)
res7: String = hello
But it is still not possible to leave out the parentheses in a(5) = "hello" because a = "hello" is the syntax to redefine a value. The shortest possible notation is a() = "hello", when you only specify the update-method like this: def update(str: String) {...}
See this blog post for a more detailed explanation on how to use the update-method.
According to the Scala Language Specification, section 1.1, = is a reserved word. You can't, therefore, override or overload it.
You can also use Scala-Virtualized, where you can override all control structures. This is nearly certainly overkill, but the option exists.

Implicit conversion with implicit parameter

I'm implementing a Java interface with a lot of methods with Object parameters, which in my case are really Strings containing user names:
public interface TwoFactorAuthProvider {
boolean requiresTwoFactorAuth(Object principal);
... //many more methods with the same kind of parameter
}
I'm trying to use implicit conversion to convert these to User objects in my implementation:
class TwoFactorAuthProviderImpl(userRepository: UserRepository)
extends TwoFactorAuthProvider {
def requiresTwoFactorAuth(user: User): Boolean = {
...
}
}
When I define the conversion in the companion object of my class, it is picked up just fine and my class compiles:
object TwoFactorAuthProviderImpl {
implicit def toUser(principal: Any): User = {
null //TODO: do something useful
}
}
However, to be able to do the conversion, I need access to the user repository, which the TwoFactorAuthProviderImpl instance has, but the companion object does not. I thought I could possibly use an implicit parameter to pass it:
implicit def toUser(principal: Any)(implicit repo: UserRepository): User = {
val email = principal.asInstanceOf[String]
repo.findByEmail(email)
}
But with the implicit parameter, the conversion is no longer picked up by the compiler (complaining that I'm not implementing the interface).
Is there a way to get the implicit conversion that I want, or is this outside the scope of what you can do with implicits?
This should work just fine - can you supply the exact compilation error? Not implementing what interface? It looks like you would have to declare as follows:
class TwoFactorAuthProviderImpl(implicit userRepository: UserRepository)
Here's an example for the REPL to show that implicits can have implicits; I'm using paste mode to ensure that module X is the companion object of the class X
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class X(i: Int, s: String)
object X { implicit def Int_Is_X(i: Int)(implicit s: String) = X(i, s) }
// Exiting paste mode, now interpreting.
defined class X
defined module X
scala> val i: X = 4
<console>:9: error: value X is not a member of object $iw
val i: X = 4
^
But if we add an implicit string in scope
scala> implicit val s = "Foo"
s: java.lang.String = Foo
scala> val i: X = 4
i: X = X(4,Foo)
Implicits advice
Don't go overboard with implicit conversions - I think you are going too far in this sense - the principal is implicitly a mechanism by which you can discover a user, it is not implicitly a user itself. I'd be tempted to do something like this instead:
implicit def Principal_Is_UserDiscoverable(p: String) = new {
def findUser(implicit repo: UserRepository) = repo.findUser(p)
}
Then you can do "oxbow".findUser
Thanks to Oxbow's answer, I now have it working, this is only for reference.
First of all, a value that should be passed as an implicit must itself be marked implicit:
class TwoFactorAuthProviderImpl(implicit userRepository: UserRepository) ...
Second, implicit conversions are nice and all, but a method implementation signature must still match the signature of its declaration. So this does not compile, even though there is a conversion from Any to User:
def requiresTwoFactorAuth(principal: User): Boolean = { ... }
But leaving the parameter as Any, as in the declaration, and then using it as a user works just fine:
def requiresTwoFactorAuth(principal: Any): Boolean = {
principal.getSettings().getPhoneUsedForTwoFactorAuthentication() != null
}
Also, the conversion really doesn't have to be in the companion object in this case, so in the end, I left the implicit parameters out.
The full source code:
class TwoFactorAuthProviderImpl(userRepository: UserRepository)
extends TwoFactorAuthProvider {
private implicit def toUser(principal: Any): User = {
val email = principal.asInstanceOf[String]
userRepository.findByEmail(email)
}
def requiresTwoFactorAuth(principal: Any): Boolean = {
//using principal as a User
principal.getSettings().getPhoneUsedForTwoFactorAuthentication() != null
}
...
}