I tried the following code:
class C(val g: Int => Int)
object C {
object A extends {
var f: Int => Int = x => x
} with C(x => f(x) + 1)
def main(args: Array[String]): Unit = {
println(A.g(3))
}
}
It can compile (at scala version 2.12.2), but throws Exception at runtime:
Exception in thread "main" java.lang.ExceptionInInitializerError
at pkg1.C$.main(C.scala:14)
at pkg1.C.main(C.scala)
Caused by: java.lang.ClassCastException: scala.runtime.ObjectRef cannot be cast to scala.Function1
at pkg1.C$A$.<init>(C.scala:10)
at pkg1.C$A$.<clinit>(C.scala)
... 2 more
Why does this happen?
This is probably a scalac bug (/unintended interference of features of early initialization of variables and lambda type references' class type) caused by using method handles for functions starting from 2.12:
Scala and Java 8 interop is also improved for functional code, as methods that take functions can easily be called in both directions using lambda syntax. The FunctionN classes in Scala’s standard library are now Single Abstract Method (SAM) types, and all SAM types are treated uniformly – from type checking through code generation. No class file is generated for a lambda; invokedynamic is used instead.
Edit: I could not find a good workaround for this problem besides changing the var to val, but I guess that is not possible in your use case.
Related
I have the following snippet that (I think) defines a method addNumber1(x:T):T on a generic type T which is a subtype of AnyVal and has a method +(s:Int):T.
def addNumber1[T <: AnyVal {def +(s:Int):T}](x:T):T = {x + 1}
addNumber1(31) // compiles but throws exception
java.lang.NoSuchMethodException: java.lang.Integer.$plus(int)
at java.lang.Class.getMethod(Class.java:1786)
at .reflMethod$Method1(<console>:8)
at .addNumber1(<console>:8)
... 33 elided
I tried adding import scala.language.reflectiveCalls to suppress a feature warning but still get the error.
I am able to use this when working with AnyRef or Any as below:
def addNumber1[T <: Any {def +(s:Int):T}](x:T):T = {x + 1}
class Foo(s:String) {def +(i:Int) = new Foo((s+1).toString)} // random code
class Bar(s:Foo) {def +(i:Int) = new Bar(new Foo(i.toString))} // random code
addNumber1(new Foo("1")) // works
addNumber1(new Bar(new Foo("1"))) // works
addNumber1(1) // compiles but gives exception
You run into an intersection of quite a few features:
So far as the initial stages of Scala compiler are concerned (including typechecking), Int does have an (overloaded) + method. But this "method" is treated specially by the later stages (as are all methods on Int, because it isn't really a class).
Methods called + and defined in Scala are translated to methods called $plus in bytecode, since + is not a legal identifier there. Since + on Int is special, as mentioned above, this doesn't apply to it. Since the structural types are implemented using Java reflection, your addNumber1 looks somewhat like
def addNumber1(x: Object) = x.getClass.getMethod("$plus").invoke(x, 1)
To call addNumber1 on an int, it has to be boxed to Integer first, because int is not an object. Integer, not being a Scala type, doesn't have a $plus method. In Scala you can write something like val x: Integer = ...; x + 1, but this uses an implicit conversion which Java reflection has no idea about.
I think the problem has nothing to do with AnyVal, AnyRef Or Any.
addNumber1(new Foo("1"))
This works because you indeed defined a Foo class that provides an implementation of def +(s:Int):T.
addNumber1(1)
This doesn't work because Integer class doesn't provide it, as is mentioned in the exception:
java.lang.NoSuchMethodException: java.lang.Integer.$plus(int)
I am writing a Scala macro (Scala 2.11) where I'd like to obtain the tree representing an implicit variable inside the macro using inferImplicitValue, evaluate that syntax tree, and use the value. I have actually done this, but it doesn't seem to work in all circumstances[1]. I constructed a simplified example where it fails.
// a class for implicit evidence
class DemoEvidence(val value: Int)
// define 'foo' method for invoking the macro
object demoModule {
def foo: Int = macro DemoMacros.fooImpl
}
class DemoMacros(val c: whitebox.Context) {
import c.universe._
def fooImpl: Tree = {
val vInt = try {
// get the tree representing the implicit value
val impl = c.inferImplicitValue(typeOf[DemoEvidence], silent = false)
// print it out
println(s"impl= $impl")
// try to evaluate the tree (this is failing)
val eval = c.eval(c.Expr[DemoEvidence](c.untypecheck(impl.duplicate)))
eval.value
} catch {
case e: Throwable => {
// on failure print out the failure message
println(s"Eval failed with: $e\nStack trace:\n${e.printStackTrace}")
0
}
}
q"$vInt" // return tree representing the integer value
}
}
If I compile the above, and then invoke it:
object demo {
implicit val demoEvidence: DemoEvidence = new DemoEvidence(42)
val i: Int = demoModule.foo
}
I see the compilation fail in the following way:
impl= demo.this.demoEvidence
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal$$anonfun$compile$1.apply(ToolBoxFactory.scala:275)
...
Full output at:
https://gist.github.com/erikerlandson/df48f64329be6ab9de9caef5f5be4a83
So, you can see it is finding the tree for the declared implicit value demo.this.demoEvidence, but evaluation of that tree is failing. I have seen this basic approach work elsewhere in my project. Not sure what the difference is, and why it fails here.
[1] UPDATE: If the implicit value is defined in a (sub)project, and compiled, and then used exterior to that project, it works as expected. That was the case where this approach is working for me.
So the question is whether that's just a fundamental constraint I have to live with, or if there is some clever workaround, or if this is a "bug" with inferring implicit values inside macros that might be fixed.
UPDATE: I filed a Scala issue for this: https://github.com/scala/scala-dev/issues/353
From the look of the stack trace, the eval is expecting object demo to exist in classfile form for execution, which makes sense given that the value you're trying to compute depends on val demoEvidence which is a member of object demo.
But the eval is happening during the typechecking of object demo so the classfile doesn't exist yet, hence the error. In the version with the implicit value defined in a subproject I imagine the subproject is compiled first, hence the classfiles required for the eval exist and so evaluation proceeds as you were expecting.
In my app, I am keeping track of the number of credits the user has. To add some type checking, I'm using a Credits class similar to this one:
case class Credits(val numCredits: Int) extends Ordered[Credits] {
...
}
Suppose I have a function def accept(creds: Credits): Unit that I want to call. Would there be a way for me to call it with
process(Credits(100))
process(0)
but not with this?
process(10)
I.e., I'd like to provide an implicit conversion only from the literal 0 and none other. Right now, I just have val Zero = Credits(0) in the companion object and I think that's rather good practice, but I'd be interested in an answer anyway, including other comments, like:
could this be done with macro implicit conversions in 2.10?
should Credits rather extend AnyVal and not be a case class in 2.10?
This kind of compile-time checking are the good terrain to use macros, which will be available in 2.10
A very smart guy named Jason Zaugg has already implemented something similar to what you need, but it applies to regex: Regex Compile Time checking.
You might want to look to its Macrocosm to see how it is done and how you could code your own macros with the same purpose.
https://github.com/retronym/macrocosm
If you really want to know more about Macros, firstly I would say that you need to be brave because the documentation is scarce for now and the API is likely to change. Jason Zaugg works compiles fine with 2.10-M3 but I am not sure it will works with the newer version.
If you want to start with some readings:
A good entry point is the scalamacros website http://scalamacros.org/ and the SIP document https://docs.google.com/document/d/1O879Iz-567FzVb8kw6N5OBpei9dnbW0ZaT7-XNSa6Cs/edit?pli=1
If you have time, you might also wants to read Eugene Burmako presentation:
http://scalamacros.org/talks/2012-04-28-MetaprogrammingInScala210.pdf
Now, getting to the topic, Scala macros are CATs : "Compile-time AST Transformations".
The abstract syntax tree is the way the compiler represents your source code. The compiler applies consequent transformations to the AST and at the last step it actual generates the java bytecode.
Let's now look to Jason Zaugg code:
def regex(s: String): scala.util.matching.Regex = macro regexImpl
def regexImpl(c: Context)(s: c.Expr[String]): c.Expr[scala.util.matching.Regex] = {
import c.universe._
s.tree match {
case Literal(Constant(string: String)) =>
string.r // just to check
c.reify(s.splice.r)
}
}
As you seen regex is a special function which takes a String and returns a Regex, by calling macro regexImpl
A macro function receives a context in the first parameter lists, and in second argument list the parameters of the macro under the form of c.Expr[A] and returns a c.Expr[B]. Please note that c.Expr is a path dependent type, i.e. it is a class defined inside the Context, so that if you have two context the following is illegal
val c1: context1.Expr[String] = ...
val c2: context2.Expr[String] = ...
val c3: context1.Expr[String] = context2.Expr[String] // illegal , compile error
Now if you look what happens in the code:
There is a match block which matches on s.tree
If s.tree is a Literal, containing a constant String , string.r is called
What's going on here is that there is an implicit conversion from string to StringOps defined in Predef.scala, which is automatically imported in the compilation every scala source
implicit def augmentString(x: String): StringOps = new StringOps(x)
StringOps extends scala.collection.immutable.StringLike, which contains:
def r: Regex = new Regex(toString)
Since macros are executed at compile time, this will be executed at compile time, and compilation will fail if an exception will be thrown (that is the behaviour of creating a regex from an invalid regex string)
Note: unluckily the API is very unstable, if you look at http://scalamacros.org/documentation/reference.html you will see a broken link towards the Context.scala. The right link is https://github.com/scala/scala/blob/2.10.x/src/reflect/scala/reflect/makro/Context.scala
Basically, you want dependent types. Why Scala supports a limited form of dependent types in path dependent types, it can't do what you ask.
Edmondo had a great idea in suggesting macros, but it has some limitations. Since it was pretty easy, I implemented it:
case class Credits(numCredits: Int)
object Credits {
implicit def toCredits(n: Int): Credits = macro toCreditsImpl
import scala.reflect.makro.Context
def toCreditsImpl(c: Context)(n: c.Expr[Int]): c.Expr[Credits] = {
import c.universe._
n.tree match {
case arg # Literal(Constant(0)) =>
c.Expr(Apply(Select(Ident("Credits"), newTermName("apply")),
List(arg)))
case _ => c.abort(c.enclosingPosition, "Expected Credits or 0")
}
}
}
Then I started up REPL, defined accept, and went through a basic demonstration:
scala> def accept(creds: Credits) { println(creds) }
accept: (creds: Credits)Unit
scala> accept(Credits(100))
Credits(100)
scala> accept(0)
Credits(0)
scala> accept(1)
<console>:9: error: Expected Credits or 0
accept(1)
^
Now, to the problem:
scala> val x = 0
x: Int = 0
scala> accept(x)
<console>:10: error: Expected Credits or 0
accept(x)
^
In other words, I can't track properties of the value assigned to identifiers, which is what dependent types would allow me to do.
But the whole strikes me as wasteful. Why do you want just 0 to be converted? It seems you want a default value, in which case the easiest solution is to use a default value:
scala> def accept(creds: Credits = Credits(0)) { println(creds) }
accept: (creds: Credits)Unit
scala> accept(Credits(100))
Credits(100)
scala> accept()
Credits(0)
Use could use an implicit partial function:
scala> case class Credits(val numCredits: Int)
defined class Credits
scala> def process(c: Credits) = {}
process: (c: Credits)Unit
scala> implicit def i2c:PartialFunction[Int, Credits] = { case 0 => Credits(0) }
i2c: PartialFunction[Int,Credits]
Allows you
scala> process(Credits(12))
and
scala> process(0)
But:
scala> process(12)
scala.MatchError: 12 (of class java.lang.Integer)
at $anonfun$i2c$1.apply(<console>:9)
at $anonfun$i2c$1.apply(<console>:9)
at .<init>(<console>:12)
at .<clinit>(<console>)
at .<init>(<console>:11)
at .<clinit>(<console>)
at $print(<console>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)
at scala.tools.nsc.interpreter.IMain$Request$$anonfun$14.apply(IMain.sca
la:920)
at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:4
3)
at scala.tools.nsc.io.package$$anon$2.run(package.scala:25)
at java.lang.Thread.run(Unknown Source)
Edit: But yes, the compiler will still allow process(12) resulting in a match error at runtime.
Why does this code throw an exception?
val x = new { def toInt(n: Int) = n*2 }
x.toInt(2)
scala.tools.nsc.symtab.Types$TypeError: too many arguments for method toInteger: (x$1: java.lang.Object)java.lang.Integer
at scala.tools.nsc.typechecker.Contexts$Context.error(Contexts.scala:298)
at scala.tools.nsc.typechecker.Infer$Inferencer.error(Infer.scala:207)
at scala.tools.nsc.typechecker.Infer$Inferencer.errorTree(Infer.scala:211)
at scala.tools.nsc.typechecker.Typers$Typer.tryNamesDefaults$1(Typers.scala:2350)
...
I'm using scala 2.9.1.final
Clearly a compiler bug (the compiler crashes, and REPL tells you That entry seems to have slain the compiler.). It's not signalling there's anything wrong with your code.
You're creating a single instance of type AnyRef{def toInt(n: Int): Int}, so creating a singleton object as Kyle suggests might be a better way of going about it. Or create a named class / trait that you insantiate, which works fine.
EDIT: As Luigi Plinge suggested, it's a compiler bug.
Maybe you want something like this...
object x {
def toInt(n:Int) = n * 2
}
scala> x.toInt(2)
res0: Int = 4
OK, in the question about 'Class Variables as constants', I get the fact that the constants are not available until after the 'official' constructor has been run (i.e. until you have an instance). BUT, what if I need the companion singleton to make calls on the class:
object thing {
val someConst = 42
def apply(x: Int) = new thing(x)
}
class thing(x: Int) {
import thing.someConst
val field = x * someConst
override def toString = "val: " + field
}
If I create companion object first, the 'new thing(x)' (in the companion) causes an error. However, if I define the class first, the 'x * someConst' (in the class definition) causes an error.
I also tried placing the class definition inside the singleton.
object thing {
var someConst = 42
def apply(x: Int) = new thing(x)
class thing(x: Int) {
val field = x * someConst
override def toString = "val: " + field
}
}
However, doing this gives me a 'thing.thing' type object
val t = thing(2)
results in
t: thing.thing = val: 84
The only useful solution I've come up with is to create an abstract class, a companion and an inner class (which extends the abstract class):
abstract class thing
object thing {
val someConst = 42
def apply(x: Int) = new privThing(x)
class privThing(x: Int) extends thing {
val field = x * someConst
override def toString = "val: " + field
}
}
val t1 = thing(2)
val tArr: Array[thing] = Array(t1)
OK, 't1' still has type of 'thing.privThing', but it can now be treated as a 'thing'.
However, it's still not an elegant solution, can anyone tell me a better way to do this?
PS. I should mention, I'm using Scala 2.8.1 on Windows 7
First, the error you're seeing (you didn't tell me what it is) isn't a runtime error. The thing constructor isn't called when the thing singleton is initialized -- it's called later when you call thing.apply, so there's no circular reference at runtime.
Second, you do have a circular reference at compile time, but that doesn't cause a problem when you're compiling a scala file that you've saved on disk -- the compiler can even resolve circular references between different files. (I tested. I put your original code in a file and compiled it, and it worked fine.)
Your real problem comes from trying to run this code in the Scala REPL. Here's what the REPL does and why this is a problem in the REPL. You're entering object thing and as soon as you finish, the REPL tries to compile it, because it's reached the end of a coherent chunk of code. (Semicolon inference was able to infer a semicolon at the end of the object, and that meant the compiler could get to work on that chunk of code.) But since you haven't defined class thing it can't compile it. You have the same problem when you reverse the definitions of class thing and object thing.
The solution is to nest both class thing and object thing inside some outer object. This will defer compilation until that outer object is complete, at which point the compiler will see the definitions of class thing and object thing at the same time. You can run import thingwrapper._ right after that to make class thing and object thing available in global scope for the REPL. When you're ready to integrate your code into a file somewhere, just ditch the outer class thingwrapper.
object thingwrapper{
//you only need a wrapper object in the REPL
object thing {
val someConst = 42
def apply(x: Int) = new thing(x)
}
class thing(x: Int) {
import thing.someConst
val field = x * someConst
override def toString = "val: " + field
}
}
Scala 2.12 or more could benefit for sip 23 which just (August 2016) pass to the next iteration (considered a “good idea”, but is a work-in-process)
Literal-based singleton types
Singleton types bridge the gap between the value level and the type level and hence allow the exploration in Scala of techniques which would typically only be available in languages with support for full-spectrum dependent types.
Scala’s type system can model constants (e.g. 42, "foo", classOf[String]).
These are inferred in cases like object O { final val x = 42 }. They are used to denote and propagate compile time constants (See 6.24 Constant Expressions and discussion of “constant value definition” in 4.1 Value Declarations and Definitions).
However, there is no surface syntax to express such types. This makes people who need them, create macros that would provide workarounds to do just that (e.g. shapeless).
This can be changed in a relatively simple way, as the whole machinery to enable this is already present in the scala compiler.
type _42 = 42.type
type Unt = ().type
type _1 = 1 // .type is optional for literals
final val x = 1
type one = x.type // … but mandatory for identifiers