scala reflection field class - scala

I'm trying to get the type of an attribute that refers to a custom class, I just get that it's of type Object
My code:
class Edge[N <% Node](var from : N, var to : N) {
def toXml(c: Class): xml.Elem = {
<edge>{
for(field: Field <- classOf[this.type].getDeclaredFields)
yield <field name={field.name} tpe={field.tpe.toString()}>{ this.getClass().getMethods.find(_.getName() == field.name).get.invoke(this) }</field>
}</edge>
}
So the problem here is that I need to switch between the java Field and scala Field: apparently there is no such thing as this.getClass in scala? So I need to go through Java to get the class?
However this seems to only result in Objects as types?

EDIT: The revised question is: Should scala.reflect.Field or java.lang.reflect.Field be used?
Answer: Always[*] use java.lang.reflect.Field, and in general java reflection for two reasons:
That is what is returned by xxx.getClass().getDeclaredFields()
The following comment is next to the definition of scala.reflect.Field
.
/** This type is required by the compiler and <b>should not be used in client code</b>. */
case class Field(override val fullname: String, tpe: Type) extends GlobalSymbol(fullname)
[*] At least for now. reflection is coming soon to Scala.
--
Original answer:
It would help if you posted the class code as well, but it seems that the field is declared as Object. getType returns the declaration class of the field.
From Field#getType():
Returns a Class object that identifies the declared type for the field
represented by this Field object.
class Foo {
var bar: String = "string"
var bar2: java.lang.Object = "string"
}
for (field <- new Foo().getClass.getDeclaredFields()) {
println("field=" + field.getName() + " " + field.getType.toString())
}
gives
field=bar class java.lang.String
field=bar2 class java.lang.Object
If you want the type of the instance, then you will have to do a .getClass() on the instance in the normal way.

Related

What is a difference between refinement type and anonymous subclass in Scala 3?

Anonymous class definition is
An anonymous class is a synthetic subclass generated by the Scala
compiler from a new expression in which the class or trait name is
followed by curly braces. The curly braces contains the body of the
anonymous subclass, which may be empty. However, if the name following
new refers to a trait or class that contains abstract members, these
must be made concrete inside the curly braces that define the body of
the anonymous subclass.
Refinement type definition is
A type formed by supplying a base type a number of members inside
curly braces. The members in the curly braces refine the types that
are present in the base type. For example, the type of “animal that
eats grass” is Animal { type SuitableFood = Grass }
-- Both definitions are taken from book Programming in Scala Fifth Edition by Martin Odersky and others.
What is the difference? Can you illustrate it with simple examples?
Let's see my code example which compiles:
abstract class A:
type T
// anonymous class
var o1 = new A { type T = String }
// refinement type
var o2: A { type T = String } = null
o1 = o2 // OK
o2 = o1 // OK
It seems to me that refinement type is a handy way to create a new type, which anonymous class does implicitly.
As Dmytro Mitin pointed out in [1] and [2], the main difference is the same as the difference between class and type.
A type restricts the possible values to which a variable can refer, or an expression can produce, at run time. Refinement type is still a type, which may be used instead of defining a new class.
Without using the refinement type in the example, you would have to define a new class.
class AString extends A:
type T = String
A class is a blueprint for objects. Once you define a class, you can create objects from the class blueprint with the keyword new.
Type and class are different (and actually orthogonal) concepts. Types belong to type theory, classes belong to OOP. Classes exist in bytecode, types mostly don't exist in bytecode (if they are not persisted to runtime specially or if they don't correspond to classes obviously).
What is the difference between a class and a type in Scala (and Java)?
What is the difference between Type and Class?
https://typelevel.org/blog/2017/02/13/more-types-than-classes.html
new A { type T = String } is a shorthand for
{
class AImpl extends A {
type T = String
}
new AImpl
}
If you define an anonymous class
val o1 = new A { type T = String }
the type of o1 can be, for example, refined
val o1: A { type T = String } = new A { type T = String }
or even structural
val o1: A { type T = String; def foo(): Unit } = new A {
type T = String
def foo(): Unit = println("foo")
}
or not refined if we statically upcast, just
val o1: A = new A { type T = String }
So defining an anonymous class doesn't mean that the type of variable is a refinement type.
On the other hand, you can consider refined type
type X = A { type T = String }
val o2: A { type T = String } = null
not introducing an anonymous class. The only class in bytecode now is A, there is no AImpl (until you instantiate new ...).
Scala refined types can be compared with refinement types in type theory (or programming languages with dependent types), i.e. (dependent) types endowed with a predicate.

Scala - Create user-type with method

I have a generic class which takes one type, and I have a parameter from that type. The issue is that I need to use a method from this parameter (in my problem, I need to use the method getTimestamp).
I can't have a trait or an abstract class because I know that, at some point, the type will be a Java Class that I can't modified.
I tried something like this :
type InputWithTimestamp = {def getTimestamp: Long}
class Foo[Input <: InputWithTimestamp](f : Input) {
def printTimestamp = { println(f.getTimestamp) }
}
class Test(timestamp : Long) {
def getTimestamp = timestamp
}
val t = new Test(1000)
val f = new Foo(t)
f.printTimestamp
And it is perfectly working.
But as I said, at some point I need to use a java class as a type.
And here is my problem :
Even if the java class defined a method getTimestamp which returns a long, I have the following error :
Error: inferred type arguments [MyJavaClass] do not conform to class Foo's type parameter bounds [Input <: InputWithTimestamp]
So what can I do to have a generic type which defined this method without needing to modify my java class ?
The problem in my case was that I didn't use parentheses to declare my method getTimestamp (because you get a warning in IDEA if you do so).
But in that case, I need the parentheses, otherwise the java method getTimestamp doesn't match the scala method
type InputWithTimestamp = {def getTimestamp: Long}
works perfectly.

Context bounds for type members or how to defer implicit resolution until member instantiation

In the following example, is there a way to avoid that implicit resolution picks the defaultInstance and uses the intInstance instead? More background after the code:
// the following part is an external fixed API
trait TypeCls[A] {
def foo: String
}
object TypeCls {
def foo[A](implicit x: TypeCls[A]) = x.foo
implicit def defaultInstance[A]: TypeCls[A] = new TypeCls[A] {
def foo = "default"
}
implicit val intInstance: TypeCls[Int] = new TypeCls[Int] {
def foo = "integer"
}
}
trait FooM {
type A
def foo: String = implicitly[TypeCls[A]].foo
}
// end of external fixed API
class FooP[A:TypeCls] { // with type params, we can use context bound
def foo: String = implicitly[TypeCls[A]].foo
}
class MyFooP extends FooP[Int]
class MyFooM extends FooM { type A = Int }
object Main extends App {
println(s"With type parameter: ${(new MyFooP).foo}")
println(s"With type member: ${(new MyFooM).foo}")
}
Actual output:
With type parameter: integer
With type member: default
Desired output:
With type parameter: integer
With type member: integer
I am working with a third-party library that uses the above scheme to provide "default" instances for the type class TypeCls. I think the above code is a minimal example that demonstrates my problem.
Users are supposed to mix in the FooM trait and instantiate the abstract type member A. The problem is that due to the defaultInstance the call of (new MyFooM).foo does not resolve the specialized intInstance and instead commits to defaultInstance which is not what I want.
I added an alternative version using type parameters, called FooP (P = Parameter, M = Member) which avoids to resolve the defaultInstance by using a context bound on the type parameter.
Is there an equivalent way to do this with type members?
EDIT: I have an error in my simplification, actually the foo is not a def but a val, so it is not possible to add an implicit parameter. So no of the current answers are applicable.
trait FooM {
type A
val foo: String = implicitly[TypeCls[A]].foo
}
// end of external fixed API
class FooP[A:TypeCls] { // with type params, we can use context bound
val foo: String = implicitly[TypeCls[A]].foo
}
The simplest solution in this specific case is have foo itself require an implicit instance of TypeCls[A].
The only downside is that it will be passed on every call to foo as opposed to just when instantiating
FooM. So you'll have to make sure they are in scope on every call to foo. Though as long as the TypeCls instances are in the companion object, you won't have anything special to do.
trait FooM {
type A
def foo(implicit e: TypeCls[A]): String = e.foo
}
UPDATE: In my above answer I managed to miss the fact that FooM cannot be modified. In addition the latest edit to the question mentions that FooM.foo is actually a val and not a def.
Well the bad news is that the API you're using is simply broken. There is no way FooM.foo wille ever return anything useful (it will always resolve TypeCls[A] to TypeCls.defaultInstance regardless of the actual value of A). The only way out is to override foo in a derived class where the actual value of A is known, in order to be able to use the proper instance of TypeCls. Fortunately, this idea can be combined with your original workaround of using a class with a context bound (FooP in your case):
class FooMEx[T:TypeCls] extends FooM {
type A = T
override val foo: String = implicitly[TypeCls[A]].foo
}
Now instead of having your classes extend FooM directly, have them extend FooMEx:
class MyFoo extends FooMEx[Int]
The only difference between FooMEx and your original FooP class is that FooMEx does extend FooM, so MyFoo is a proper instance of FooM and can thus be used with the fixed API.
Can you copy the code from the third party library. Overriding the method does the trick.
class MyFooM extends FooM { type A = Int
override def foo: String = implicitly[TypeCls[A]].foo}
It is a hack, but I doubt there is anything better.
I do not know why this works the way it does. It must be some order in which the type alias are substituted in the implicitly expression.
Only an expert in the language specification can tell you the exact reason.

How to update a mongo record using Rogue with MongoCaseClassField when case class contains a scala Enumeration

I am upgrading existing code from Rogue 1.1.8 to 2.0.0 and lift-mongodb-record from 2.4-M5 to 2.5.
I'm having difficulty writing MongoCaseClassField that contains a scala enum, that I really could use some help with.
For example,
object MyEnum extends Enumeration {
type MyEnum = Value
val A = Value(0)
val B = Value(1)
}
case class MyCaseClass(name: String, value: MyEnum.MyEnum)
class MyMongo extends MongoRecord[MyMongo] with StringPk[MyMongo] {
def meta = MyMongo
class MongoCaseClassFieldWithMyEnum[OwnerType <: net.liftweb.record.Record[OwnerType], CaseType](rec : OwnerType)(implicit mf : Manifest[CaseType]) extends MongoCaseClassField[OwnerType, CaseType](rec)(mf) {
override def formats = super.formats + new EnumSerializer(MyEnum)
}
object myCaseClass extends MongoCaseClassFieldWithMyEnum[MyMongo, MyCaseClass](this)
/// ...
}
When we try to write to this field, we get the following error:
could not find implicit value for evidence parameter of type
com.foursquare.rogue.BSONType[MyCaseClass]
.and(_.myCaseClass setTo myCaseClass)
We used to have this working in Rogue 1.1.8, by using our own version of the MongoCaseClassField, which made the #formats method overridable. But that feature was included into lift-mongodb-record in 2.5-RC6, so we thought this should just work now?
Answer coming from : http://grokbase.com/t/gg/rogue-users/1367nscf80/how-to-update-a-record-with-mongocaseclassfield-when-case-class-contains-a-scala-enumeration#20130612woc3x7utvaoacu7tv7lzn4sr2q
But more convenient directly here on StackOverFlow:
Sorry, I should have chimed in here sooner.
One of the long-standing problems with Rogue was that it was too easy to
accidentally make a field that was not serializable as BSON, and have it
fail at runtime (when you try to add that value to a DBObject) rather than
at compile time.
I introduced the BSONType type class to try to address this. The upside is
it catches BSON errors at compile time. The downside is you need to make a
choice when it comes to case classes.
If you want to do this the "correct" way, define your case class plus a
BSONType "witness" for that case class. To define a BSONType witness, you
need to provide serialization from that type to a BSON type. Example:
case class TestCC(v: Int)
implicit object TestCCIsBSONType extends BSONType[TestCC] {
override def asBSONObject(v: TestCC): AnyRef = {
// Create a BSON object
val ret = new BasicBSONObject
// Serialize all the fields of the case class
ret.put("v", v.v)
ret
}
}
That said, this can be quite burdensome if you're doing it for each case
class. Your second option is to define a generic witness that works for any
case class, if you have a generic serialization scheme:
implicit def CaseClassesAreBSONTypes[CC <: CaseClass]: BSONType[CC] =
new BSONType[CC] {
override def asBSONObject(v: CC): AnyRef = {
// your generic serialization code here, maybe involving formats
}
}
Hope this helps,

Initializing and using a field in an abstract generic class in Scala

I have something like this in scala:
abstract class Point[Type](n: String){
val name = n
var value: Type = _
}
So far so good. The problem comes in a class that extends Point.
case class Input[Type](n:String) extends Point(n){
def setValue(va: Type) = value = va
}
On the setValue line I have this problem:
[error] type mismatch;
[error] found : va.type (with underlying type Type)
[error] required: Nothing
[error] def setValue(va: Type) = value = va
I have tried to initialize with null and null.asInstanceOf[Type] but the result is the same.
How can I initialize value so it can be used in setValue?
You should specify that Input implements Point with the generic type Type because for now, as it is not specified, it is considered as Nothing (I guess the compiler can't infer it from the setValue method). So you have to do the following:
case class Input[Type](n:String) extends Point[Type](n){
def setValue(va: Type) = value = va
}
More information
I answered this question for the compilation error (it does compile on scala 2.9.0.1). Moreover I saw this case class as the implementation for an existing type, like 'Int'. The usage of _ is of course a bad idea in the abstract class, however it is not prohibited, but the _ is not always a null, it is the default value, for exemple: var x:Int = _ will assign the value 0 to x.
Try the following:
package inputabstraction
abstract class Point[T](n:String){
def value: T
val name = n
}
case class Input[T](n:String, value:T) extends Point[T](n)
object testTypedCaseClass{
def test(){
val foo = Input("foo", "bar")
println(foo)
}
}
A simple Application to check that it works:
import inputabstraction._
object TestApp extends Application{
testTypedCaseClass.test()
}
Explanation
The first mistake you are making is case class Input[Type](n:String) extends Point(n){. Point is a typed class, and so when you are calling the superclass constructor with extends Point(n) you need to specify the type of Point. This is done like this: extends Point[T](n), where T is the Type you are planning to use.
The second error is that you are both defining and declaring value:T here: var value: Type = _. In this statement, _ is a value. Its value is Nothing. The scala compiler infers from this that Point[T] is Point[Nothing]. Thus when you attempt to set it to a type in the body of your setValue method, you must set it to Nothing, which is probably not what you want. If you attempt to set it to anything besides Nothing, you will get the type mismatch from above, because value is typed as Nothing due to your use of _.
The third mistake is using var instead of val or def. val and def can be overridden interchangeably, which means that subtypes can override with either val or def, and the scala compiler will figure it out for you. It is best practice to define vals as functions using def in abstract classes and traits, because the initialization order of subtype constructors is a very difficult thing to get right (there is an algorithm for how the compiler decides how to construct a class from its supertypes). TL#DR === use def in supertypes. Case class parameters are automatically generate val fields, which, since you are extending a Point, will create a val value field that overrides the def value field in Point[T].
You can get away with all this Type||T abstraction in Scala because of type inference and the fact that Point is abstract, therefore making value extendable via val.
The preferred way of doing dependency injection like this is the cake pattern, but this example I have provided works for your use-case.