scala> val hi = "Hello \"e"
hi: String = Hello "e
scala> val hi = "go"
hi: String = go
Within same REPL session why its allowing me to declare variable hi with same name ?
scala> hi
res1: String = go
scala> hi="new"
<console>:8: error: reassignment to val
hi="new"
^
This error i understood we cannot reassign val
The interesting design feature of the REPL is that your two definitions are translated to:
object A {
val greeting = "hi"
}
object B {
val greeting = "bye"
}
A subsequent usage will import the last definition:
object C {
import B.greeting
val message = s"$greeting, Bob." // your code
}
You can witness the exact wrapping strategy with scala -Xprint:parser:
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
import $line4.$read.$iw.$iw.greeting;
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
val message = StringContext("", ", Bob.").s(greeting)
}
}
In the first piece of code I believe this is a "feature" of the REPL allowing your to redefine hi. Suppose you are working through building a small piece of code in the REPL then it might be helpful to go back and change a prior definition without rewriting the others to use a different value.
The following code would give an error error: x is already defined as value x when compiling with scalac.
class Foo{
val x = "foo"
val x = "foo"
}
In the second piece of code you are trying to reassign a val which cannot be changed. This is what you would expect.
Related
I have a program that can yield an abstract TypeTag when executed:
class TypeResolving extends FunSpec {
import org.apache.spark.sql.catalyst.ScalaReflection.universe._
val example = new Example
it("can convert") {
val t1 = implicitly[TypeTag[example.T]]
println(t1)
}
}
object TypeResolving {
class Example {
type T = Map[String, Int]
}
val example = new Example
}
The execution results in:
TypeTag[TypeResolving.this.example.T]
Since in this case example.T is already defined, I would also like to get the actual TypeTag:
TypeTag[Map[String,Int]]
How do I get there?
Try dealias
def dealias[T, T1](typeTag: TypeTag[T]): TypeTag[T1] = backward(typeTag.tpe.dealias)
val typeTag = implicitly[TypeTag[TypeResolving.example.T]] //TypeTag[TypeResolving.example.T]
val typeTag1 = dealias(typeTag) //TypeTag[scala.collection.immutable.Map[String,Int]]
val typeTag2 = implicitly[TypeTag[Map[String, Int]]] //TypeTag[Map[String,Int]]
val typeTag3 = dealias(typeTag2) //TypeTag[scala.collection.immutable.Map[String,Int]]
typeTag1 == typeTag3 //true
How to get the aliased type of a type alias in scala runtime?
Get a TypeTag from a Type? (backward is from here)
There is a note in Cay Horstmann's book "Scala for the Impatient" about the apply method:
Occasionally, the () notation conflicts with another Scala feature:
implicit parameters. For example, the expression "Bonjour".sorted(3)
yields an error because the sorted method can optionally be called
with an ordering, but 3 is not a valid ordering.
The solution is to assign "Bonjour".sorted to a variable and call apply on it, for example:
val result = "Bonjour".sorted
result(3)
Or call apply explicitly:
"Bonjour".sorted.apply(3)
But why this doesn't work and produces a compile error:
("Bonjour".sorted)(3)
The sorted method returns a String, which can be imlicitly converted to a StringOps and parentheses are used to wrap the string expression.
Why compiler doesn't accept to call the apply method of a StringOps?
You can use -Xprint:parser to see that the parens are discarded early:
scala> implicit class x(val s: String) { def scaled(implicit i: Int) = s * i }
defined class x
scala> "hi".scaled(5)
res0: String = hihihihihi
scala> { implicit val n: Int = 5 ; "hi".scaled }
res1: String = hihihihihi
scala> "hi".scaled(5)(3)
res2: Char = i
scala> { implicit val n: Int = 5 ; ("hi".scaled)(3) }
res3: String = hihihi
scala> :se -Xprint:parser
scala> { implicit val n: Int = 5 ; ("hi".scaled)(3) }
[[syntax trees at end of parser]] // <console>
package $line8 {
object $read extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
import $line3.$read.$iw.$iw.x;
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
val res4 = {
implicit val n: Int = 5;
"hi".scaled(3)
}
}
}
}
}
res4: String = hihihi
scala>
The extra parens do nothing. The compiler just sees an application expr(args). Because it's an application, you don't get "implicit application" conversion.
In any case, the meaning of scaled, a method, depends on the expected type.
The reason we expect the extra parens to make a difference is that parens override precedence of operators. But (x) is just x.
Possibly the spec is actually clear about this:
e(args) requires that e be applicable to the args. In particular, the args are typechecked according to the parameter types of e.
e(args) is taken as e.apply(args) if e is a value, but scaled is a method.
You're hoping for "implicit application" to insert the implicit args, but that only applies when e is not already applied. Or that (e)(args) could be taken as (e(_))(args), that is, (x => e(x))(arg).
When written as e.apply(arg), the e is not an application like e(arg), so you benefit from conversions like implicit application.
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> val hi = "Hello \"e"
hi: String = Hello "e
scala> val hi = "go"
hi: String = go
Within same REPL session why its allowing me to declare variable hi with same name ?
scala> hi
res1: String = go
scala> hi="new"
<console>:8: error: reassignment to val
hi="new"
^
This error i understood we cannot reassign val
The interesting design feature of the REPL is that your two definitions are translated to:
object A {
val greeting = "hi"
}
object B {
val greeting = "bye"
}
A subsequent usage will import the last definition:
object C {
import B.greeting
val message = s"$greeting, Bob." // your code
}
You can witness the exact wrapping strategy with scala -Xprint:parser:
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
import $line4.$read.$iw.$iw.greeting;
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
val message = StringContext("", ", Bob.").s(greeting)
}
}
In the first piece of code I believe this is a "feature" of the REPL allowing your to redefine hi. Suppose you are working through building a small piece of code in the REPL then it might be helpful to go back and change a prior definition without rewriting the others to use a different value.
The following code would give an error error: x is already defined as value x when compiling with scalac.
class Foo{
val x = "foo"
val x = "foo"
}
In the second piece of code you are trying to reassign a val which cannot be changed. This is what you would expect.
I'm attempting to write a macro that would wrap a function and deducting a parameter from the value its invocation will be assigned to.
object TestMacros {
def foo(name: String): String = name.toUpper
def bar = macro barImpl
def barImpl(c: Context): c.Expr[String] = {
import c.universe._
//TODO extract value name (should be baz)
c.Expr[String](Apply(
Select(newTermName("TestMacros"), newTermName("foo")), // Probably wrong, just typed it quickly for demonstration purposes
List(Literal(Constant("test"))))) // Should replace test by value name
}
}
object TestUsage {
val baz = bar // should be BAZ
}
I don't know if this is clear enough. I've investigated both c.prefix and c.macroApplication without success. I'm using Scala 2.10.2 without the macro-paradise compiler plugin.
This is very possible. I know, because I've done something like it before. The trick is to search the enclosing tree for a value whose right-hand side has the same position as the macro application:
import scala.language.experimental.macros
import scala.reflect.macros.Context
object TestMacros {
def foo(name: String): String = name.toUpperCase
def bar = macro barImpl
def barImpl(c: Context): c.Expr[String] = {
import c.universe._
c.enclosingClass.collect {
case ValDef(_, name, _, rhs)
if rhs.pos == c.macroApplication.pos => c.literal(foo(name.decoded))
}.headOption.getOrElse(
c.abort(c.enclosingPosition, "Not a valid application.")
)
}
}
And then:
scala> object TestUsage { val baz = TestMacros.bar }
defined module TestUsage
scala> TestUsage.baz
res0: String = BAZ
scala> class TestClassUsage { val zab = TestMacros.bar }
defined class TestClassUsage
scala> (new TestClassUsage).zab
res1: String = ZAB
Note that you can apply foo at compile-time, since you know the name of the val at compile-time. If you wanted it to be applied at runtime that would also be possible, of course.
I had a similar problem when I wanted to simplify some property initializations. So your code helped me to find out how that is possible, but I got deprecation warnings. As scala macros evolve the enclosingClass got deprecated in Scala 2.11. The documentation states to use c.internal.enclosingOwner instead. The quasiquotes feature makes things easier now - my sample to retrieve just the name as in val baz = TestMacros.getName looks like this:
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
object TestMacros {
def getName(): String = macro getNameImpl
def getNameImpl(c: Context)() = {
import c.universe._
val term = c.internal.enclosingOwner.asTerm
val name = term.name.decodedName.toString
// alternatively use term.fullName to get package+class+value
c.Expr(q"${name}")
}
}