I am using Active Annotations to generate fields in my classes and am having difficulty discovering how to expand field initializer expressions. Without initializers the code looks like this
class JavaFxPropertyProcessor implements TransformationParticipant<MutableFieldDeclaration>{
def private transform(MutableFieldDeclaration field, extension TransformationContext context){
fields.forEach[transform(context)]
}
def private transform(MutableFieldDeclaration field, extension TransformationContext context){
val clazz = field.declaringType as MutableClassDeclaration
val theClass = SomeJavaClass //any non-parameterised java class here
clazz.addField("myField")[
type = theClass.newTypeReference
initializer = ['''new <<toJavaCode(theClass.newTypeReference()>>(this)''']
]
}
}
This works fine when the field has no initializer. Ocassionally, I would like the field to have an initializer and that works fine for int and bool literals by just dumping the initializer as a string into the expression
val theInitializer = field.initializer //this is not null
clazz.addField("myField2")[
type = theClass.newTypeReference
initializer = [
'''new <<toJavaCode(theClass.newTypeReference()>>(this, <<theInitializer.toString>>)'''
]
]
When the initializer is a list literal, say #[1,2,3] for example, then clearly the naive initializer.toString technique doesn't work since it creates java code such as
val myField = new List<Integer>(#[1,2,3]);
So how to I get to evaluate/expand the field.initializer (which is of type org.eclipse.xtend.lib.macro.expression) in order to java-ise it for my initializers?
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.
When inheriting from a Java class with public members, using scala's override modifier raises compilation error like so:
Error:(67, 22) overriding variable userId in class Logon of type String;
value userId has incompatible type
override val userId = s.user
^
The java class looks something along the following lines:
public class Logon {
public String userId = "";
}
and the scala code:
class MyLogon extends Logon {
override val userId : String = "abc"
}
Removing the modifier results in:
Error:(72, 7) overriding variable userId in class Logon of type String;
value userId needs `override' modifier
val userId: String = s.user
^
Why is this? Is it a bug? There are related questions e.g. 16607517 but these seem to be changing the visibility of the fields; that's not the case here - they're all public.
Believe this is with scalac-2.10.4.
It is impossible to override public fields defined in Java because of how it is implemented in Scala:
A public field (val user: String) is represented internally as a combination of private field (say, private val user$1: String) and public accessor method (def user: String = user$1). It is not allowed to override a field with a method, thus the compile error.
There is currently no way to omit the public accessor method generation in Scala, so you'll have to find other ways to implement what you want - either by defining a common trait or interface, or by using another field name, or by wrapping the Java Logon into a Scala Logon with proper superclass constructs.
Scala interoperates extremely well with Java, but the interop is not perfect, unfortunately.
You cannot override member variables.
This should not be confused with how scala allows to override val & var which works because scala compiler generates getter and setter methods for them.
I have an abstract class with a default value for its parameter.
I don't want to have to reuse the default value in the constructor of all the possible implementations.
abstract class Place(val place: String = "World")
class Message(val message: String = "Hello", p: String) extends Place(p) {
override def toString = s"$message $place"
}
What I want to get
new Message("Hi", "Universe") = "Hi Universe" // Ok
new Message("Hi") = "Hi World" // Doesn't work, second parameter is required
new Message() = "Hello World" // Doesn't work, second parameter is required
I considered using an auxiliary constructor omitting the second parameter, but it doesn't help since you can't call super constructors outside of the main constructor.
I want to know how to do it, or why it is not possible. I'm not looking for a workaround, like not using inheritance.
I'm afraid that is not possible. Quite simply, you ARE passing a value to Place constructor, so it wont use the default, whatever its value might be. If you don't mind having a var instead of a val, here is a variant that works for your 3 cases:
abstract class Place(var place: String = "World")
class Message(val message: String = "Hello") extends Place()
{
def this(message: String, place: String) = {
this(message)
this.place = place
}
override def toString = s"$message $place"
}
Constructors in Scala are a little of a mess IMHO. Sometimes a better answer is just to use factory apply() methods on a companion object, which are more flexible.
You can reuse the default value in a more elegant way:
object Place {
val defaultPlace = "World"
}
abstract class Place(val place: String = Place.defaultPlace)
class Message(val message: String = "Hello", p: String = Place.defaultPlace) extends Place(p) {
override def toString = s"$message $place"
}
Is it possible to do this? (I'm using scala 2.10) To call a method that requires that the object has a function named "fullName", but the object being built with the Dynamic trait. The compiler complains, but maybe I'm doing it wrong.
I don't need this for any job, I'm just learning the language.
import scala.language.dynamics
object Main extends App {
class MyStatic {
private var privateName = ""
var lastName = ""
def name_= (n: String) {
privateName = n
}
def name = s"***$privateName***"
def fullName = s"$name $lastName"
}
class MyDynamic extends scala.Dynamic {
val map = collection.mutable.Map[String, String]()
def selectDynamic(key: String): String = map(key)
def updateDynamic(key: String)(value: String) {
map += key -> value
}
def applyDynamic(key: String)(value: Any*) = key match {
case "fullName" => {
val name = map("name")
val lastName = map("lastName")
s"$name $lastName"
}
}
}
def showFullName(o: { def fullName: String }) = s"My full name is $o.fullName"
println("Starting App...")
val s = new MyStatic
s.name = "Peter"
s.lastName = "Parker"
println(showFullName(s))
val d = new MyDynamic
d.name = "Bruce"
d.lastName = "Wayne"
println(showFullName(d))
}
The structural type { def fullName: String } basically means "any type with a no-arg method named fullName returning a String.
MyDynamic has no such method, and thus does not comply with this structural type. The fact that MyDynamic extends scala.Dynamic is irreleveant: it means that for any instance of it, you can perform what looks like a call to fullName, but it does not mean that MyDynamic (as a type) has any such member.
So the short answer is no, you cannot mix dynamic objects with structural typing like that.
For completeness, I must add that it could be made to work as you expected, but it would require a special provision from the compiler (namely, the compiler could consider than any type extending scala.Dynamic -- and implementing the required lookup methods -- is compatible with any structural typing, and implement the call not via reflection as is normally done, but by calling the corresponding lookup method).
You are trying to glue together two completely different things. While structural typing is also sometimes compared to 'duck-typing', its feature is exactly the use of static type information (even if on the use site the byte code will call reflection). Per definition, your dynamic type does not have such static type information. So you will never be able to convince the Scala compiler that your dynamic type has a method that can be statically verified to exist.
The only workaround would be to allow any type in showFullName and use reflection to call fullName (again, I'm not sure if this plays out with a dynamic object).
On the other hand, Scala will let you do anything with dynamic types, handing the responsibility over to you:
def showFullName(o: Dynamic) = s"My full name is $o.fullName"
println(showFullName(d))
Just started on unit testing using Scala and had this basic question.
class Test {
ClassToBeTested testObject;
#Before
void initializeConstructor() {
testObject = new ClassToBeTested(//Blah parameters);
}
#Test
//Blah
}
The above example in Java shows that I can just declare an object of type ClassToBeTested and initialize it later. Can this be done in Scala? I tried it
class Test {
var testObject = new ClassToBeTested()
#Before def initializeConstructor() {
//I do not know how to proceed here!!!!!!
}
#Test def testOne() {
//Some test
}
}
I don't want to do everything inside the testOne() because I want to use the object in different tests. The parameters of the constructor are mocks and in JUnit I know that mocks are not initialized if I initialize an object globally and not inside #Before.
Here is how you can make it:
class Test {
var testObject: ClassToBeTested = _
#Before
def initializeConstructor() {
testObject = new ClassToBeTested()
}
#Test
def testOne() {
//Some test
}
}
More on underscore init.
You can also read more about this in Section 18.2 Reassignable variables and properties of Programming in Scala book. Here is quote, that can be helpful to you:
More precisely, an initializer "= _" of a field assigns a zero value to that field. The zero value depends on the field's type. It is 0 for numeric types, false for booleans, and null for reference types. This is the same as if the same variable was defined in Java without an initializer.
Note that you cannot simply leave off the "= _" initializer in Scala. If you had written:
var celsius: Float
this would declare an abstract variable, not an uninitialized one