scala.Enumerator.nextName and .nextNameOrNull currently read:
/** The string to use to name the next created value. */
protected var nextName: Iterator[String] = _
private def nextNameOrNull =
if (nextName != null && nextName.hasNext) nextName.next() else null
nextNameOrNull is subsequently called to get the name to use for the item being created in the Enumeration.
How does this code actually achieve this?
When I copy-paste it into a simple example:
class MyBaseClass extends Serializable {
/** The string to use to name the next created value. */
protected var nextName: Iterator[String] = _
private def nextNameOrNull =
if (nextName != null && nextName.hasNext) nextName.next() else null
protected final def Value(): Val = Val(nextNameOrNull)
case class Val(name:String)
}
object MyObject extends MyBaseClass {
val myValue = Value
println("Hello from MyObject, myValue: " + myValue)
}
it prints: Hello from MyObject, myValue: Val(null) instead of the hoped for Val(myValue)
What do I need to add to make it work?
In Scala JVM, Enumeration uses reflection to get the name of the val to which a Value was assigned to if nextNameOrNull returns null.
In Scala.js, we do not have this luxury (no reflection support). Therefore, the Scala.js compiler special cases scala.Enumeration, so that code that uses it can work.
If you want to implement some method that knows the name of the val it is assigned to, have a look at sbt's project macro. Scala's Enumerations could have been implemented that way starting 2.10, but are older.
nextNameOrNull isn't not working anymore even for original Scala - as passing a sequence of names to constructor is deprecated and removed.
Here is the execution for 2.11.2 using original scala's Enumeration (not the replaced one from scala-js):
scala> object MyObject extends Enumeration {
| val MyValue1, MyValue2 = Value
|
| println("nextName: " + nextName)
| }
defined object MyObject
scala> MyObject
nextName: null //still null
In 2.10.x nextName used inside one of constructor to specify names explicitly as sequence (which is removed in 2.11.x):
#deprecated("Names should be specified individually or discovered via reflection", "2.10.0")
def this(initial: Int, names: String*) = {
this(initial)
this.nextName = names.iterator
}
}
Now this constructor is removed and nextName is just a dead code. Scala uses populateNameMap() to provide names for nameOf (if they're not specified:
private def populateNameMap() {
val fields = getClass.getDeclaredFields
def isValDef(m: JMethod) = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
// The list of possible Value methods: 0-args which return a conforming type
val methods = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
classOf[Value].isAssignableFrom(m.getReturnType) &&
m.getDeclaringClass != classOf[Enumeration] &&
isValDef(m))
methods foreach { m =>
val name = m.getName
// invoke method to obtain actual `Value` instance
val value = m.invoke(this).asInstanceOf[Value]
// verify that outer points to the correct Enumeration: ticket #3616.
if (value.outerEnum eq thisenum) {
val id = Int.unbox(classOf[Val] getMethod "id" invoke value)
nmap += ((id, name))
}
}
}
So it uses reflection by default. You can explicitly specify the name for every value as it's described here.
I think same for ScalaJs, excluding that it has no populateNameMap() method as there is no such kind of reflection for JavaScript - so result for non-explicitly named parameters is:
override def toString() =
if (name != null) name //only if you did `Value("explicitName")` somwhere inside enumeration
// Scala.js specific
else s"<Unknown name for enum field #$i of class ${getClass}>"
But again, nextNameOrNull is dead in both Scala and Scala-Js - it always returns null.
Related
I want to have a collection of objects, each object a companion of a different class, which classes all share a common method defined in a superclass that can be invoked when looping through the collection with a foreach(). I want the constructors of these sibling-classes to have the same named parameters and default parameter values as each other. Finally, I want to minimize repeated code.
Thus far, I am trying to do this with case classes, since--if it worked--it would eliminate all the duplicated code of the companion-objects for each type. The problem is that if I put all these companion objects into a Set, when I take them out again I lose the default parameters and parameter names.
Here is some example code of what I am describing:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
case class caseOne(override val param: String = "default") extends MyType
case class caseTwo(override val param: String = "default") extends MyType
object Main extends App {
// I can construct instances using the companion objects' `apply()` method:
val works1 = caseOne(param = "I have been explicitly set").label
// I can construct instances that have the default parameter value
val works2 = caseOne().label
// But what I want to do is something like this:
val set = Set(caseOne, caseTwo)
for {
companion <- set
} {
val fail1 = companion() // Fails to compile--not enough arguments
val fail2 = companion(param = "not default") // Fails also as param has lost its name
val succeeds = companion("nameless param") // this works but not what I want
println(fail1.label + fail2.label) // this line is my goal
}
}
Notably if the Set has only one element, then it compiles, suggesting the inferred type of the multi-element Set lacks the parameter name--even though they are the same--and the default values. Also suggesting that if I gave the Set the right type parameter this could work. But what would that type be? Not MyType since that is the type of the companion classes rather that the objects in the Set.
I could define the companion objects explicitly, but that is the repeated code I want to avoid.
How can I loop through my collection, constructing instances of MyType subclasses on each iteration, with constructors that have my desired parameter names and default values? All while minimizing repeated code?
Update: Originally the example code showed caseOne and caseTwo as having different default values for param. That was incorrect; they are now the same.
You're not going to be able to get exactly what you want since you don't really have much control over the auto-generated companion objects. In particular for this to work they would all need to extend a common trait. This is why it fails to compile when the set has more than one companion object; even though they all have a method with the same signature, they don't extend a common trait for the compiler to utilize.
You can use a nested case class and get something very similar though:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
abstract class MyTypeHelper(default: String) {
case class Case(param: String) extends MyType
def apply(param: String) : Case = Case(param)
def apply(): Case = apply(default)
}
object One extends MyTypeHelper("default one")
object Two extends MyTypeHelper("default two")
object Example {
val works1 = One(param = "I have been explicitly set").label
val works2 = One().label
val set = Set(One, Two)
for {
companion <- set
} {
val a = companion()
val b = companion(param = "not default")
val c = companion("nameless param")
println(a.label + b.label)
}
}
Instead of having a caseOne type, you have One.Case, but it still implements MyType so you shouldn't have any issue anywhere else in the code that uses that trait.
Given the following String:
"println(\"Hello\")"
It is possible to use reflection to evaluate the code, as follows.
object Eval {
def apply[A](string: String): A = {
val toolbox = currentMirror.mkToolBox()
val tree = toolbox.parse(string)
toolbox.eval(tree).asInstanceOf[A]
}
}
However, lets say that the string contains an object with a function definition, such as:
"""object MyObj { def getX="X"}"""
Is there a way to use Scala reflection to compile the string, load it and run the function? What I have tried to do has not worked, if anyone has some example code it is very appreciated.
It depends on how strictly you define the acceptable input string. Should the object always be called MyObj? Should the method always be called getX? Should it always be 1 method or can it be multiple?
For the more general case you could try to extract all method names from the AST and generate calls to each one. The following code will call every method (and returns the result of the last one) that takes 0 arguments and is not a constructor, in some object, not taking inheritance into account:
def eval(string: String): Any = {
val toolbox = currentMirror.mkToolBox()
val tree = toolbox.parse(string)
//oName is the name of the object
//defs is the list of all method definitions
val ModuleDef(_,oName,Template(_,_,defs)) = tree
//only generate calls for non-constructor, zero-arg methods
val defCalls = defs.collect{
case DefDef(_,name,_,params,_,_)
if name != termNames.CONSTRUCTOR && params.flatten.isEmpty => q"$oName.$name"
}
//put the method calls after the object definition
val block = tree :: defCalls
toolbox.eval(q"..$block")
}
And using it:
scala> eval("""object MyObj { def bar() = println("bar"); def foo(a: String) = println(a); def getX = "x" }""")
bar
res60: Any = x
I'm trying to write a convenience function that replaces the left tree of an immutable binary tree, and I'm getting "Error occurred in an application involving default arguments" in the following replaceL method:
abstract class AbNode {
val key = null
val value = null
val leftTree:AbNode = NullNode
val rightTree:AbNode = NullNode
}
case class Node[K <:Ordered[K],V](k:K, v:V, lT:AbNode, rT:AbNode) extends AbNode {
val key:K = k
val value:V = v
val leftTree:AbNode = lT
val rightTree:AbNode = rT
}
object Node {
def replaceL[K <: Ordered[K],V](newTree:AbNode, node:Node[K,V]): Node[K,V] =
node.copy(leftTree = newTree) //<< Error occurs here
}
case object NullNode extends AbNode {
val key = null
val value = null
val leftTree = NullNode
val rightTree = NullNode
}
The copy method (and default parameters in general) use the name used in the constructor, not the field name that you assign it to (I don't know why this didn't click sooner).
In the case of a case class, the assigned fields are useless; as far as I can tell, they're simply holding a copy of a reference to the constructor value (not my original intent). I think my confusion stemmed from the fact that in C-style languages, the variables given to a constructor are later assigned to a field. In other words, the way I have my classes set-up is non-sensical, they shouldn't have any fields.
My Node class should be simply:
case class Node[K <:Ordered[K],V](k:K, v:V, leftTree:AbNode, rightTree:AbNode) extends AbNode
Which allows copy to see the value I'm referring to.
At present we have dozens of traits that contain the following method:
trait ThisTrait extends SuperTrait {
override def getList: List[String] =
List(/* invariant list of strings */) ::: super.getList
}
where "invariant" means that each instance of MyTrait has the same base list, likewise each instance of SuperTrait has the same base list, etc. It's wasteful to recompute this every time the method is called, and so I'd like to change all of these to something like the following
trait ThisTrait extends SuperTrait {
override def getList: List[String] = GetList.getList(super.getList)
}
// see edit below for a modified version of htis
private object GetList {
private val baseList = (/* invariant list of strings */)
private var thisList = null
def getList(superList: List[String]) = {
if(thisList == null) thisList = baseList ::: superList
thisList
}
}
which isn't too awful since super.getList will also be returning a (mostly) precomputed list, however I'd prefer if I could do something like the following
private object GetList {
private val thisList = (/* invariant list of strings */) ::: MyTrait.super.getList
def getList = thisList
}
I could do something like this via MyTrait.getClass.getSuperclass.getMethod("getList"), but I was hoping that there was a type-safe way of doing this (besides hard-coding a reference to SuperTrait's GetList object)
Edit: I could improve this via
private object GetList {
private val baseList = (/* invariant list of strings */)
private var thisList = null
def getList(superList: => List[String]) = {
if(thisList == null) thisList = baseList ::: superList
thisList
}
}
so I won't call super.getList unless it's needed, however I'm still interested in knowing if there's a type-safe way of doing something like MyTrait.super.getList
No, and it's a good thing. If it was possible, you could break class invariants in many cases. I am also pretty sure that if you call the method via reflection, you'll get the same implementation as calling MyTrait's getList, and an infinite loop.
I found this explanation on how to propagate overriden member values to superclass constructors by using lazy val. Unfortunately, the article does not explain why this works.
I understand than non-lazy values cannot be assigned twice and that therefore, no value is available in a super constructor since the value assignment in the super class constructor must be skiped in order to not lock the variable to another value. However, how can the println statement - which is executed in the super constructor, i.e. before the new lazy value is asigned - already know about this new value? Am I confusing something about the execution order? Or is println somehow only evaluating its argument after the object is constructed?
It's pretty simple. You just should note that all fields and lazy fields are getter methods.
val getter returns value of private[this] field. private[this] field assignment is located in primary constructor:
class Test {
val field = 1
}
means something like this:
class Test {
private[this] val _field: Int = _
def field = _field
{ // constructor
_field = 1
}
}
So before constructor field returns default value.
lazy val evaluates block of code using double check lock and than returns result:
class Test {
lazy val field = 1
}
means something like this:
class Test {
private[this] val _field: Int = _
#volatile private[this] val _flag: Boolean = _
def field = {
if (! _flag) {
synchronized {
if (! _flag) {
_field = 1 // code block
_flag = true
}
}
}
_field
}
}
So lazy val has nothing with constructor, you'll get same result before and after constructor.
You could check this using scalac -Xprint:mixin test.scala.