This page is no longer maintained — Please continue to the home page at www.scala-lang.org

scalabeans

10 replies
Andreas W 2
Joined: 2011-07-30,
User offline. Last seen 42 years 45 weeks ago.

I have decided to look into scalabeans for an introspection need that
I have. I have found it ingeniously straightforward and simple, a
wonderful design. It seems much underused, as I have found very little
on the web except its web sites and an occasional general comment
about it. Apparently, you can introspect with it beyond erasure by use
of Manifests, and from early experiments I have found that, for
example, properties like prop: Option[SomeClass] are correctly
detected. I had, however, a property of type "Option[Double]" which
was apparently introspected as "Option[Object]". This puts a huge dent
in my enthusiasm, as this is the kind of type I need to resolve. Is
this a known behavior, or have I done something wrong?

I have

case class Rec(name: String, value: Double, opt: Option[Double], obj:
Option[SomeClass])

I do "descriptor[Rec].properties.mkString("\n ")", and I get types
out like this:

String
Double
Option[Object]
Option[SomeClass]

i.e. it correctly represents Option[SomeClass], but not
Option[Double].

Any ideas what I could be doing wrong?

Thanks,

Andreas

Andreas W 2
Joined: 2011-07-30,
User offline. Last seen 42 years 45 weeks ago.
Re: scalabeans

Ah, turns out I missed the up-to-date discussion here:
http://code.google.com/p/scalabeans/wiki/Blog. I checked out the
development branch, and now I get the right results. See test
definition below for what I was interested in. This is great software!

Minor quibbles: Should the primitive type names be capitalized? And
that blog is somewhat hidden on the scalabeans main page, at least
from me.

Cheers,

Andreas

package org.scalastuff.scalabeans

import org.junit.{Assert, Test}
import org.scalastuff.scalabeans.types._

class OptionRefTest {
@Test
def testCreate {
def test[T<:AnyRef:Manifest](tn: String) {
val bd = Preamble.descriptorOf[T]
Assert.assertEquals(4, bd.properties.length)
val ns = Seq("String", "double", "int", "boolean")
for ( (n, i) <- ns.zipWithIndex)
Assert.assertEquals(tn+"["+n+"]",
""+bd.properties(i).scalaType)
}
test[OptionTestBean]("Option")
test[RefTestBean]("Ref")
}
}

case class OptionTestBean(
stringOpt: Option[String], doubleOpt: Option[Double],
intOpt: Option[Int], booleanOpt: Option[Boolean]
)
case class RefTestBean(
stringOpt: Ref[String], doubleOpt: Ref[Double],
intOpt: Ref[Int], booleanOpt: Ref[Boolean]
)
case class Ref[T](x: T)

On Jul 29, 10:51 pm, Andreas W wrote:
> I have decided to look into scalabeans for an introspection need that
> I have. I have found it ingeniously straightforward and simple, a
> wonderful design. It seems much underused, as I have found very little
> on the web except its web sites and an occasional general comment
> about it. Apparently, you can introspect with it beyond erasure by use
> of Manifests, and from early experiments I have found that, for
> example, properties like prop: Option[SomeClass] are correctly
> detected. I had, however, a property of type "Option[Double]" which
> was apparently introspected as "Option[Object]". This puts a huge dent
> in my enthusiasm, as this is the kind of type I need to resolve. Is
> this a known behavior, or have I done something wrong?
>
> I have
>
> case class Rec(name: String, value: Double, opt: Option[Double], obj:
> Option[SomeClass])
>
> I do "descriptor[Rec].properties.mkString("\n  ")", and I get types
> out like this:
>
>   String
>   Double
>   Option[Object]
>   Option[SomeClass]
>
> i.e. it correctly represents Option[SomeClass], but not
> Option[Double].
>
> Any ideas what I could be doing wrong?
>
> Thanks,
>
> Andreas

DaveScala
Joined: 2011-03-18,
User offline. Last seen 1 year 21 weeks ago.
Re: scalabeans

Yeah, 0.2-SNAPSHOT definitely fixes it.

[info] == run ==
[info] Running Main
name : String // tag: 1, readonly
value : double // tag: 2, readonly
opt : Option[double] // tag: 3, readonly
obj : Option[Object] // tag: 4, readonly
[info] == run ==
[success] Successful.

Have you already found some comparison metrics about the impact on the
performance and memory usage?

The only minor thing I could find is that it only works with case
class, not with normal classes

Changing
case class Rec(name: String, value: Double, opt: Option[Double], obj:
Option[SomeClass])
into:
class Rec(name: String, value: Double, opt: Option[Double], obj:
Option[SomeClass])

[info] == run ==
[info] Running Main

[info] == run ==
[success] Successful.

Or I missed something...

DaveScala
Joined: 2011-03-18,
User offline. Last seen 1 year 21 weeks ago.
Re: scalabeans

> Or I missed something...

Of course
case classes create read-only fields for constructor parameters
implicitly

Using:
class Rec(val name: String, val value: Double, val opt:
Option[Double], val obj: Option[SomeClass])

[info] Running Main
name : String // tag: 1, readonly
value : double // tag: 2, readonly
opt : Option[double] // tag: 3, readonly
obj : Option[Object] // tag: 4, readonly
[info] == run ==
[success] Successful.

Using:
class Rec(var name: String, var value: Double, var opt:
Option[Double], var obj: Option[SomeClass])

[info] == run ==
[info] Running Main
name : String // tag: 1
value : double // tag: 2
opt : Option[double] // tag: 3
obj : Option[Object] // tag: 4
[info] == run ==
[success] Successful.

DaveScala
Joined: 2011-03-18,
User offline. Last seen 1 year 21 weeks ago.
Re: scalabeans

Hmm, in 0.2-SNAPSHOT is Option[SomeClass] changed to
Option[Object] ...
What dev version did you use?

Andreas W 2
Joined: 2011-07-30,
User offline. Last seen 42 years 45 weeks ago.
Re: scalabeans

On Jul 30, 4:35 pm, Dave wrote:
> Hmm, in 0.2-SNAPSHOT is Option[SomeClass] changed to
> Option[Object] ...
> What dev version did you use?

I cloned the repository this morning. For me, the Option[SomeClass]
works, the below test runs without problems.

package org.scalastuff.scalabeans

import org.junit.{Assert, Test}
import org.scalastuff.scalabeans.types._

class OptionRefTest {
@Test
def testCreate {
def test[T<:AnyRef:Manifest](tn: String) {
val bd = Preamble.descriptorOf[T]
val ns = Seq("String", "double", "int", "boolean", "SomeClass")
Assert.assertEquals(ns.length, bd.properties.length)
for ( (n, i) <- ns.zipWithIndex)
Assert.assertEquals(tn+"["+n+"]",
""+bd.properties(i).scalaType)
}
test[OptionTestBean]("Option")
test[RefTestBean]("Ref")
}
}

case class OptionTestBean(
stringOpt: Option[String], doubleOpt: Option[Double],
intOpt: Option[Int], booleanOpt: Option[Boolean],
objOpt: Option[SomeClass]
)
case class RefTestBean(
stringOptRef: Ref[String], doubleRef: Ref[Double],
intRef: Ref[Int], booleanRef: Ref[Boolean],
objRef: Ref[SomeClass]
)
case class Ref[T](x: T)
class SomeClass

DaveScala
Joined: 2011-03-18,
User offline. Last seen 1 year 21 weeks ago.
Re: scalabeans

It seems that it only works in test mode inside the junit test
framework.
If you run it as a real compiled application Option[SomeClass]is
changed into Option[Object] and also the Refs are type erased.

I am always suspicious about test frameworks because they sometimes
change the behaviour of what you want to test. That is why I always
test it in compiled form outside the test framework.

Or do you have an example that works in compiled form?

test run
========

C:\scala-2.9.1.RC1\examples\erase>java -Xmx512M -jar "c:\sbt\sbt-
launch-0.10.1.j
ar" test
[info] Set current project to default-9123ff (in build file:/C:/
scala-2.9.1.RC1/
examples/erase/)
[info] Compiling 1 Scala source to C:\scala-2.9.1.RC1\examples\erase
\target\scal
a-2.9.1.RC1\classes...
[info] Compiling 1 Scala source to C:\scala-2.9.1.RC1\examples\erase
\target\scal
a-2.9.1.RC1\test-classes...
5==5
Option[String]==Option[String]
Option[double]==Option[double]
Option[int]==Option[int]
Option[boolean]==Option[boolean]
Option[SomeClass]==Option[SomeClass]
5==5
Ref[String]==Ref[String]
Ref[double]==Ref[double]
Ref[int]==Ref[int]
Ref[boolean]==Ref[boolean]
Ref[SomeClass]==Ref[SomeClass]
[info] Passed: : Total 1, Failed 0, Errors 0, Passed 1, Skipped 0
[success] Total time: 9 s, completed 31-jul-2011 13:57:09

compiled run
============

C:\scala-2.9.1.RC1\examples\erase>java -Xmx512M -jar "c:\sbt\sbt-
launch-0.10.1.j
ar" run
[info] Set current project to default-9123ff (in build file:/C:/
scala-2.9.1.RC1/
examples/erase/)
[info] Running Main
5==5
Option[String]==Option[String]
Option[double]==Option[double]
Option[int]==Option[int]
Option[boolean]==Option[boolean]
Option[SomeClass]==Option[Object]
5==5
Ref[String]==Object
Ref[double]==Object
Ref[int]==Object
Ref[boolean]==Object
Ref[SomeClass]==Object
[success] Total time: 2 s, completed 31-jul-2011 13:53:05

erase.scala
===========

import org.scalastuff.scalabeans._
import org.scalastuff.scalabeans.types._

object Main extends App {
def test[T<:AnyRef:Manifest](tn: String) {
val bd = Preamble.descriptorOf[T]
val ns = Seq("String", "double", "int", "boolean",
"SomeClass")
println(ns.length + "==" + bd.properties.length)
for ( (n, i) <- ns.zipWithIndex) {
println(tn+"["+n+"]" + "==" +
bd.properties(i).scalaType)
}
}
test[OptionTestBean]("Option")
test[RefTestBean]("Ref")
}

case class OptionTestBean(
stringOpt: Option[String], doubleOpt: Option[Double],
intOpt: Option[Int], booleanOpt: Option[Boolean],
objOpt: Option[SomeClass]
)
case class RefTestBean(
stringOptRef: Ref[String], doubleRef: Ref[Double],
intRef: Ref[Int], booleanRef: Ref[Boolean],
objRef: Ref[SomeClass]
)
case class Ref[T](x: T)
class SomeClass

DaveScala
Joined: 2011-03-18,
User offline. Last seen 1 year 21 weeks ago.
Re: scalabeans

Just to be sure I tested also outside of sbt java-only, but it was the
same.

C:\scala-2.9.1.RC1\examples\erase\target\scala-2.9.1.RC1>java -
cp ../../../../li
b/scala-library.jar;google-collect-1.0-
rc2.jar;erase_2.9.1.RC1-1.0.jar;C:\Users\
Dave\.ivy2\cache\org.scalastuff\scalabeans\jars\scalabeans-0.2-
SNAPSHOT.jar;C:\U
sers\Dave\.ivy2\cache\com.thoughtworks.paranamer\paranamer\jars
\paranamer-2.3.ja
r Main
5==5
Option[String]==Option[String]
Option[double]==Option[double]
Option[int]==Option[int]
Option[boolean]==Option[boolean]
Option[SomeClass]==Option[Object]
5==5
Ref[String]==Object
Ref[double]==Object
Ref[int]==Object
Ref[boolean]==Object
Ref[SomeClass]==Object

google-collect-1.0-rc2.jar can be downloaded from:
http://www.java2s.com/Code/Jar/GHI/Downloadgooglecollect10rc2jar.htm

Andreas W 2
Joined: 2011-07-30,
User offline. Last seen 42 years 45 weeks ago.
Re: scalabeans

You are right. When I run without JUnit, the below code returns:

Option[String]: Option[String]
Option[double]: Option[Object]
Option[int]: Option[Object]
Option[boolean]: Option[Object]
Option[SomeClass]: Option[SomeClass]
Ref[String]: Ref[String]
Ref[double]: Ref[Object]
Ref[int]: Ref[Object]
Ref[boolean]: Ref[Object]
Ref[SomeClass]: Ref[SomeClass]

A little better than yours, but with the Option[Val] issue not fixed.
Bummer. Not sure what to try next....

By the way, the blog-post that mentioned this issue earlier on the
scalabeans Wiki appears to have disappeared. This is not good.

Andreas

def main(args: Array[String]) {
testBean[OptionTestBean]("Option")
testBean[RefTestBean]("Ref")
}

def testBean[T<:AnyRef:Manifest](tn: String) {
val bd = descriptorOf[T]
val ns = Seq("String", "double", "int", "boolean", "SomeClass")
for ( (n, i) <- ns.zipWithIndex)
println(tn+"["+n+"]: "+bd.properties(i).scalaType)
}

case class OptionTestBean(
stringOpt: Option[String], doubleOpt: Option[Double],
intOpt: Option[Int], booleanOpt: Option[Boolean],
objOpt: Option[SomeClass]
)
case class RefTestBean(
stringOptRef: Ref[String], doubleRef: Ref[Double],
intRef: Ref[Int], booleanRef: Ref[Boolean],
objRef: Ref[SomeClass]
)
case class Ref[T](x: T)
class SomeClass

On Jul 31, 9:04 am, Dave wrote:
> Just to be sure I tested also outside of sbt java-only, but it was the
> same.
>
> C:\scala-2.9.1.RC1\examples\erase\target\scala-2.9.1.RC1>java -
> cp ../../../../li
> b/scala-library.jar;google-collect-1.0-
> rc2.jar;erase_2.9.1.RC1-1.0.jar;C:\Users\
> Dave\.ivy2\cache\org.scalastuff\scalabeans\jars\scalabeans-0.2-
> SNAPSHOT.jar;C:\U
> sers\Dave\.ivy2\cache\com.thoughtworks.paranamer\paranamer\jars
> \paranamer-2.3.ja
> r Main
> 5==5
> Option[String]==Option[String]
> Option[double]==Option[double]
> Option[int]==Option[int]
> Option[boolean]==Option[boolean]
> Option[SomeClass]==Option[Object]
> 5==5
> Ref[String]==Object
> Ref[double]==Object
> Ref[int]==Object
> Ref[boolean]==Object
> Ref[SomeClass]==Object
>
> google-collect-1.0-rc2.jar can be downloaded from:http://www.java2s.com/Code/Jar/GHI/Downloadgooglecollect10rc2jar.htm

Andreas W 2
Joined: 2011-07-30,
User offline. Last seen 42 years 45 weeks ago.
Re: scalabeans

Ah, I feel like I have made a breakthrough (of sorts...). The code I
posted was from inside an "object" declaration. On a hunch, I took the
test classes out to the package level, and voila:

Option[String]: Option[String]
Option[double]: Option[double]
Option[int]: Option[int]
Option[boolean]: Option[boolean]
Option[SomeClass]: Option[SomeClass]
Ref[String]: Ref[String]
Ref[double]: Ref[double]
Ref[int]: Ref[int]
Ref[boolean]: Ref[boolean]
Ref[SomeClass]: Ref[SomeClass]

So, it seems scalabeans only works with top-level classes, which is
still bummer, but not a show-stopper....

Andreas

On Aug 2, 3:50 pm, Andreas W wrote:
> You are right. When I run without JUnit, the below code returns:
>
> Option[String]: Option[String]
> Option[double]: Option[Object]
> Option[int]: Option[Object]
> Option[boolean]: Option[Object]
> Option[SomeClass]: Option[SomeClass]
> Ref[String]: Ref[String]
> Ref[double]: Ref[Object]
> Ref[int]: Ref[Object]
> Ref[boolean]: Ref[Object]
> Ref[SomeClass]: Ref[SomeClass]
>
> A little better than yours, but with the Option[Val] issue not fixed.
> Bummer. Not sure what to try next....
>
> By the way, the blog-post that mentioned this issue earlier on the
> scalabeans Wiki appears to have disappeared. This is not good.
>
> Andreas
>
>   def main(args: Array[String]) {
>     testBean[OptionTestBean]("Option")
>     testBean[RefTestBean]("Ref")
>   }
>
>   def testBean[T<:AnyRef:Manifest](tn: String) {
>     val bd = descriptorOf[T]
>     val ns = Seq("String", "double", "int", "boolean", "SomeClass")
>     for ( (n, i) <- ns.zipWithIndex)
>       println(tn+"["+n+"]: "+bd.properties(i).scalaType)
>   }
>
>   case class OptionTestBean(
>       stringOpt: Option[String], doubleOpt: Option[Double],
>       intOpt: Option[Int], booleanOpt: Option[Boolean],
>       objOpt: Option[SomeClass]
>   )
>   case class RefTestBean(
>       stringOptRef: Ref[String], doubleRef: Ref[Double],
>       intRef: Ref[Int], booleanRef: Ref[Boolean],
>       objRef: Ref[SomeClass]
>   )
>   case class Ref[T](x: T)
>   class SomeClass
>
> On Jul 31, 9:04 am, Dave wrote:
>
>
>
>
>
>
>
> > Just to be sure I tested also outside of sbt java-only, but it was the
> > same.
>
> > C:\scala-2.9.1.RC1\examples\erase\target\scala-2.9.1.RC1>java -
> > cp ../../../../li
> > b/scala-library.jar;google-collect-1.0-
> > rc2.jar;erase_2.9.1.RC1-1.0.jar;C:\Users\
> > Dave\.ivy2\cache\org.scalastuff\scalabeans\jars\scalabeans-0.2-
> > SNAPSHOT.jar;C:\U
> > sers\Dave\.ivy2\cache\com.thoughtworks.paranamer\paranamer\jars
> > \paranamer-2.3.ja
> > r Main
> > 5==5
> > Option[String]==Option[String]
> > Option[double]==Option[double]
> > Option[int]==Option[int]
> > Option[boolean]==Option[boolean]
> > Option[SomeClass]==Option[Object]
> > 5==5
> > Ref[String]==Object
> > Ref[double]==Object
> > Ref[int]==Object
> > Ref[boolean]==Object
> > Ref[SomeClass]==Object
>
> > google-collect-1.0-rc2.jar can be downloaded from:http://www.java2s.com/Code/Jar/GHI/Downloadgooglecollect10rc2jar.htm

DaveScala
Joined: 2011-03-18,
User offline. Last seen 1 year 21 weeks ago.
Re: scalabeans

Yes, that's it. It works here too

package declaration is necessary
and the test classes must be on top level/package level which I
already had (I forgot only declaring package erase).

package declaration is also necessary for the test class (remove it
and it doesn't work anymore).

C:\scala-2.9.1.RC1\examples\erase>sbt run

C:\scala-2.9.1.RC1\examples\erase>set SCRIPT_DIR=c:\sbt\

C:\scala-2.9.1.RC1\examples\erase>java -Xmx512M -jar "c:\sbt\sbt-
launch-0.10.1.j
ar" run
[info] Set current project to default-9123ff (in build file:/C:/
scala-2.9.1.RC1/
examples/erase/)
[info] Running erase.Main
5==5
Option[String]==Option[String]
Option[double]==Option[double]
Option[int]==Option[int]
Option[boolean]==Option[boolean]
Option[SomeClass]==Option[SomeClass]
5==5
Ref[String]==Ref[String]
Ref[double]==Ref[double]
Ref[int]==Ref[int]
Ref[boolean]==Ref[boolean]
Ref[SomeClass]==Ref[SomeClass]
[success] Total time: 2 s, completed 3-aug-2011 2:39:58

C:\scala-2.9.1.RC1\examples\erase>sbt test

C:\scala-2.9.1.RC1\examples\erase>set SCRIPT_DIR=c:\sbt\

C:\scala-2.9.1.RC1\examples\erase>java -Xmx512M -jar "c:\sbt\sbt-
launch-0.10.1.j
ar" test
[info] Set current project to default-9123ff (in build file:/C:/
scala-2.9.1.RC1/
examples/erase/)
[info] Compiling 1 Scala source to C:\scala-2.9.1.RC1\examples\erase
\target\scal
a-2.9.1.RC1\test-classes...
5==5
Option[String]==Option[String]
Option[double]==Option[double]
Option[int]==Option[int]
Option[boolean]==Option[boolean]
Option[SomeClass]==Option[SomeClass]
5==5
Ref[String]==Ref[String]
Ref[double]==Ref[double]
Ref[int]==Ref[int]
Ref[boolean]==Ref[boolean]
Ref[SomeClass]==Ref[SomeClass]
[info] Passed: : Total 1, Failed 0, Errors 0, Passed 1, Skipped 0
[success] Total time: 7 s, completed 3-aug-2011 2:40:20

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland