I've dynamically defined a Scala class, but in order to use it "properly" it needs to have a ScalaSig.
So, how might I generate a ScalaSig outside of normal compilation? Perhaps from a tree? Maybe like:
val tb = runtimeMirror(getClass.getClassLoader).mkToolBox()
val classDef = """class MyRecord(x: String)"""
val tree = showRaw(tb.parse(classDef))
But where does the pickler come in?
Thanks for any advice
-Julian
Artisanal-Pickle-Maker will reproduce a Scala pickled signature byte-for-byte (see restrictions).
Tapping into the compiler's pickler phase, as well as reuse of the Pickler's code, proved too challenging, so instead I used PickleBuffer, ShowPickled and a whole lotta diff -y to figure out how to generate arbitrary pickled Scala sigs.
Related
I have a factory that should return an implementation depending on the name.
val moduleMap = Map(Modules.moduleName -> new ModuleImpl)
def getModule(moduleName: String): Module =
moduleMap.get(moduleName) match {
case Some(m) => m
case _ =>
throw new ModuleNotFoundException(
s"$moduleName - Module could not be found.")
}
In order for each call to the "getModule" method not to create an instance, there is a map in which all the modules must be initialized in bootstrap class.
I would like to get rid of the need to do this manually(also all classes have a distinctive feature).
List of options that came to my mind:
Reflection(we can use Scala Reflection API or any thrid-party
library)
Automated process.
Need to initialize immediately at startup.
Reflection is a pain.
Metaprogramming(ScalaMeta) + Reflection
Macros only change the code, the execution happens later.
Can we move initialization process to compile time?
I know that compiler can optimize and replace code, next fragment before compilation
val a = 5 + 5
after compilation compiler change that piece to 10, can we use some directives or another tools to evaluate and execute some code at compile time and use only final value?
Do you use any framework or you write your own? I answered similar question about Guice here. You can use it without Guice as well: instead of Module you will have your Factory, which you need to initialize from somewhere, and during initialization, you will fill your map using reflection
In general I think it is the easiest approach. Alternatively, you can write macros, which just replaces part of reflective initialization, but not sure that it will give you some profit (if I understand your question right, this initialization will happen just once at startup).
I do not see how scalameta can help you? Probably, only in case if all your implementations are in source tree available to you, so you can analyze it and generate initialization (similar to macros)? Probably, this would add such plus as easier search for implementation, but will add minus: will work only on implementations in your sources.
Your example of compile-time optimization is not applicable. In your example, you talk about compile-time constant (even with arithmetic it could be a problem, see this comment), but in your question you need specific run-time behavior. So compile time could be only code generation from macros or based on scalameta from my point of view.
I'm trying to find a way to get at the symbol table (?) of the Scala compiler and dump all the type information on the methods/functions in say, a particular SBT project. The current direction I'm going is a compiler plugin, hooking into it right after the typer phase.
A bit of wandering around and I'm looking at the root mirror and inspecting the info.decls field of it, something along the lines of:
def newPhase(prev: Phase): Phase =
new StdPhase(prev) {
def apply(unit: CompilationUnit): Unit = {
val decls = global.RootClass.info.decls
val scalaz = decls.find(_.toString contains "scalaz")
println(scalaz.get.info.decls.filter(x => !x.hasMeaninglessName))
And it dumps quite a bit of stuff, but.. I still get quite a fair bit of weird output like class anonfun$reduceUnordered$1 extends ;
Wondering if I'm going in the right direction at all, and if so what should I be looking more at to just get the type signatures of methods in the project?
You are certainly walking the right direction. You can see a full solution in https://github.com/CANVE/extractor. As you have shown, some symbols are "synthetic", such as the case when an anonymous function has been used in the source code. So how much you may want to abstract away those symbols from any "data dump" that you pull out, is up to the specific task you wish to accomplish.
Back when reflection was still incipient, on the days of Scala 2.10.0 milestones, I asked a question about how could I use it to see the trees of code snippets from REPL. The excellent answer went further than I asked, and showed how they can be used to parse and evaluate trees as well, so I went ahead and tried to use that on a little project I had going on today.
Unfortunately, code parsed and evaluated that way doesn't seem to see any REPL definition:
scala> val x = 1
x: Int = 1
scala> import scala.tools.reflect.ToolBox
import scala.tools.reflect.ToolBox
scala> val tb = scala.reflect.runtime.universe.runtimeMirror(
getClass.getClassLoader).mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = ...
scala> tb.eval(tb.parse("x"))
scala.tools.reflect.ToolBoxError: reflective compilation has failed:
not found: value x
Is there a way to get it to recognize definitions made on REPL?
Recently I dug into repl, when trying to make it support type macros, so I'm well equipped to explain why it doesn't work. Getting it to work would be the next step :)
I know that you know that every snippet entered into repl gets wrapped into some boilerplate before being compiled. Therefore that x ends up being a field in a nested-nested-nested object in a package with a weird name.
Apparently, repl keeps track of all defined symbols and then injects the necessary imports along with the boilerplate it generates. Therefore subsequent lines can see that x unqualified. To the contrast, toolboxes simply reuse repl's classloader, but don't do anything about the imports, hence the failure.
A workaround would be to somehow get to an object representing a repl, ask it about defined symbols and then generate corresponding imports into the code that you feed to a toolbox. If you file a ticket, I'll try to code up a workaround after the 2.10.1 code freeze madness ends (supposedly, end of this week).
In groovy one can do:
class Foo {
Integer a,b
}
Map map = [a:1,b:2]
def foo = new Foo(map) // map expanded, object created
I understand that Scala is not in any sense of the word, Groovy, but am wondering if map expansion in this context is supported
Simplistically, I tried and failed with:
case class Foo(a:Int, b:Int)
val map = Map("a"-> 1, "b"-> 2)
Foo(map: _*) // no dice, always applied to first property
A related thread that shows possible solutions to the problem.
Now, from what I've been able to dig up, as of Scala 2.9.1 at least, reflection in regard to case classes is basically a no-op. The net effect then appears to be that one is forced into some form of manual object creation, which, given the power of Scala, is somewhat ironic.
I should mention that the use case involves the servlet request parameters map. Specifically, using Lift, Play, Spray, Scalatra, etc., I would like to take the sanitized params map (filtered via routing layer) and bind it to a target case class instance without needing to manually create the object, nor specify its types. This would require "reliable" reflection and implicits like "str2Date" to handle type conversion errors.
Perhaps in 2.10 with the new reflection library, implementing the above will be cake. Only 2 months into Scala, so just scratching the surface; I do not see any straightforward way to pull this off right now (for seasoned Scala developers, maybe doable)
Well, the good news is that Scala's Product interface, implemented by all case classes, actually doesn't make this very hard to do. I'm the author of a Scala serialization library called Salat that supplies some utilities for using pickled Scala signatures to get typed field information
https://github.com/novus/salat - check out some of the utilities in the salat-util package.
Actually, I think this is something that Salat should do - what a good idea.
Re: D.C. Sobral's point about the impossibility of verifying params at compile time - point taken, but in practice this should work at runtime just like deserializing anything else with no guarantees about structure, like JSON or a Mongo DBObject. Also, Salat has utilities to leverage default args where supplied.
This is not possible, because it is impossible to verify at compile time that all parameters were passed in that map.
Yes, I know it's considered lazy by the non-Pythonistas. The reason I ask is that documentation is still woefully lacking in many Scala libraries (e.g. Scala-dbc, but that's not all I'm looking at), and if I could see the attributes of an object/class at runtime, I could at least figure out what's available. Thanks.
Scala does not have a reflection API. The only way to access this information is to use the Java reflection API. This has the disadvantage that the structure may change as the way Scala is represented in Java classes and interfaces may change in the future.
scala> classOf[AnyRef].getMethods
res0: Array[java.lang.reflect.Method] = Array(public final void ...
Some specific type information that is present in the byte code can be accessed with the ScalaSigParser.
import tools.scalap.scalax.rules.scalasig._
import scala.runtime._
val scalaSig = ScalaSigParser.parse(classOf[RichDouble])
That's one of my main uses for REPL. Type the object's name, dot, and then TAB and it will show all available methods.
It isn't perfect. For one thing, it shows protected methods, which won't be available unless you are extending the class. For another thing, it doesn't show methods available through implicit conversion.
And, of course, the IDEs are all capable of doing that.
You might want something like the following which would give you what you need. In this case, it operates on a String, obviously.
val testStr = "Panda"
testStr.getClass.getMethods.foreach(println)
Does that work?
You may want to use this little helper to beef up the REPL