scala-play: Scaladoc location

147 views
Skip to first unread message

Brian Troutwine

unread,
Jun 5, 2011, 6:48:17 PM6/5/11
to play-fr...@googlegroups.com
Hello, all.

Where can I find the scaladocs for scala-play? I'd like to pull off
something like this:

def count(jid:String):Int = SQL(
"""
select count(abu.created)
from ActiveBridgeUser as abu
join PlatonicBridgeUser as pbu on abu.pUserId=pbu.id
where pbu.jid={jid}
"""
).on("jid" -> jid).collect { case Row(total:Int) => total }

but without api docs I cannot figure out where to proceed with "Error
raised is : value collect is not a member of
play.db.anorm.SimpleSql[play.db.anorm.Row]"

--
Brian L. Troutwine

Sadek Drobi

unread,
Jun 6, 2011, 12:00:21 AM6/6/11
to play-fr...@googlegroups.com
 def count(jid:String):Int = SQL(
   """
   select count(abu.created)
   from ActiveBridgeUser as abu
     join PlatonicBridgeUser as pbu on abu.pUserId=pbu.id
   where pbu.jid={jid}
   """
   ).on("jid" -> jid).as(scalar[Int])

Or

 def count(jid:String):Int = SQL(
   """
   select count(abu.created)
   from ActiveBridgeUser as abu
     join PlatonicBridgeUser as pbu on abu.pUserId=pbu.id
   where pbu.jid={jid}
   """
   ).on("jid" -> jid).apply().collect{ case Row(total:Int) => total }

"apply" will execute the Query and you should execute the query before collecting resulting.

Sadek




--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.




--
www.sadekdrobi.com
ʎdoɹʇuǝ

Brian Troutwine

unread,
Jun 6, 2011, 9:03:27 AM6/6/11
to play-fr...@googlegroups.com
Thanks,

On Mon, Jun 6, 2011 at 12:00 AM, Sadek Drobi <sadek...@gmail.com> wrote:
>  def count(jid:String):Int = SQL(
>    """
>    select count(abu.created)
>    from ActiveBridgeUser as abu
>      join PlatonicBridgeUser as pbu on abu.pUserId=pbu.id
>    where pbu.jid={jid}
>    """
>    ).on("jid" -> jid).as(scalar[Int])

This results in a runtime error:

java.lang.RuntimeException: TypeDoesNotMatch(int and class java.lang.Long)
at scala.Predef$.error(Predef.scala:58)
at play.db.anorm.Sql$.as(Anorm.scala:984)
at play.db.anorm.Sql$class.as(Anorm.scala:919)
at play.db.anorm.SimpleSql.as(Anorm.scala:829)
at models.BridgeUser$.count(models.scala:57)
at ModelCrudTests$$anonfun$1.apply$mcV$sp(Tests.scala:22)
at ModelCrudTests$$anonfun$1.apply(Tests.scala:19)
at ModelCrudTests$$anonfun$1.apply(Tests.scala:19)
at org.scalatest.FlatSpec$$anon$2.apply(FlatSpec.scala:2563)
at org.scalatest.Suite$class.withFixture(Suite.scala:1509)
at ModelCrudTests.withFixture(Tests.scala:8)
at org.scalatest.FlatSpec$class.runTest(FlatSpec.scala:2560)
at ModelCrudTests.org$scalatest$BeforeAndAfterEach$$super$runTest(Tests.scala:8)
at org.scalatest.BeforeAndAfterEach$class.runTest(BeforeAndAfterEach.scala:167)
at ModelCrudTests.runTest(Tests.scala:8)
at org.scalatest.FlatSpec$$anonfun$org$scalatest$FlatSpec$$runTestsInBranch$1.apply(FlatSpec.scala:2485)
at org.scalatest.FlatSpec$$anonfun$org$scalatest$FlatSpec$$runTestsInBranch$1.apply(FlatSpec.scala:2474)
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
at scala.collection.immutable.List.foreach(List.scala:45)
at org.scalatest.FlatSpec$class.org$scalatest$FlatSpec$$runTestsInBranch(FlatSpec.scala:2473)
at org.scalatest.FlatSpec$class.runTests(FlatSpec.scala:2687)
at ModelCrudTests.runTests(Tests.scala:8)
at org.scalatest.Suite$class.run(Suite.scala:1804)
at ModelCrudTests.org$scalatest$FlatSpec$$super$run(Tests.scala:8)
at org.scalatest.FlatSpec$class.run(FlatSpec.scala:2758)
at ModelCrudTests.run(Tests.scala:8)
at org.scalatest.tools.SuiteRunner.run(SuiteRunner.scala:59)
at org.scalatest.tools.ScalaTestRunner$.run(ScalaTestRunner.scala:58)
at org.scalatest.tools.ScalaTestRunner$.runSuiteClass(ScalaTestRunner.scala:17)
at play.scalasupport.ScalaPlugin.runTest(ScalaPlugin.scala:91)
at play.plugins.PluginCollection.runTest(PluginCollection.java:628)
at play.test.TestEngine.run(TestEngine.java:94)
at controllers.TestRunner.run(TestRunner.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at play.mvc.ActionInvoker.invokeWithContinuation(ActionInvoker.java:543)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:499)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:475)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:470)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:158)
at play.server.PlayHandler$NettyInvocation.execute(PlayHandler.java:220)
at play.Invoker$Invocation.run(Invoker.java:265)
at play.server.PlayHandler$NettyInvocation.run(PlayHandler.java:200)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:206)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)

> Or
>  def count(jid:String):Int = SQL(
>    """
>    select count(abu.created)
>    from ActiveBridgeUser as abu
>      join PlatonicBridgeUser as pbu on abu.pUserId=pbu.id
>    where pbu.jid={jid}
>    """
>    ).on("jid" -> jid).apply().collect{ case Row(total:Int) => total }

This results in: "type mismatch; found :
scala.collection.immutable.Stream[Int] required: Int" Changing the
last line to:

).on("jid" -> jid).apply().collect{ case Row(total:Int) => total }.head

results in:

java.util.NoSuchElementException: head of empty stream
at scala.collection.immutable.Stream$Empty$.head(Stream.scala:506)
at scala.collection.immutable.Stream$Empty$.head(Stream.scala:504)
at models.BridgeUser$.count(models.scala:57)
at ModelCrudTests$$anonfun$1.apply$mcV$sp(Tests.scala:22)
at ModelCrudTests$$anonfun$1.apply(Tests.scala:19)
at ModelCrudTests$$anonfun$1.apply(Tests.scala:19)
at org.scalatest.FlatSpec$$anon$2.apply(FlatSpec.scala:2563)
at org.scalatest.Suite$class.withFixture(Suite.scala:1509)
at ModelCrudTests.withFixture(Tests.scala:8)
at org.scalatest.FlatSpec$class.runTest(FlatSpec.scala:2560)
at ModelCrudTests.org$scalatest$BeforeAndAfterEach$$super$runTest(Tests.scala:8)
at org.scalatest.BeforeAndAfterEach$class.runTest(BeforeAndAfterEach.scala:167)
at ModelCrudTests.runTest(Tests.scala:8)
at org.scalatest.FlatSpec$$anonfun$org$scalatest$FlatSpec$$runTestsInBranch$1.apply(FlatSpec.scala:2485)
at org.scalatest.FlatSpec$$anonfun$org$scalatest$FlatSpec$$runTestsInBranch$1.apply(FlatSpec.scala:2474)
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
at scala.collection.immutable.List.foreach(List.scala:45)
at org.scalatest.FlatSpec$class.org$scalatest$FlatSpec$$runTestsInBranch(FlatSpec.scala:2473)
at org.scalatest.FlatSpec$class.runTests(FlatSpec.scala:2687)
at ModelCrudTests.runTests(Tests.scala:8)
at org.scalatest.Suite$class.run(Suite.scala:1804)
at ModelCrudTests.org$scalatest$FlatSpec$$super$run(Tests.scala:8)
at org.scalatest.FlatSpec$class.run(FlatSpec.scala:2758)
at ModelCrudTests.run(Tests.scala:8)
at org.scalatest.tools.SuiteRunner.run(SuiteRunner.scala:59)
at org.scalatest.tools.ScalaTestRunner$.run(ScalaTestRunner.scala:58)
at org.scalatest.tools.ScalaTestRunner$.runSuiteClass(ScalaTestRunner.scala:17)
at play.scalasupport.ScalaPlugin.runTest(ScalaPlugin.scala:91)
at play.plugins.PluginCollection.runTest(PluginCollection.java:628)
at play.test.TestEngine.run(TestEngine.java:94)
at controllers.TestRunner.run(TestRunner.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at play.mvc.ActionInvoker.invokeWithContinuation(ActionInvoker.java:543)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:499)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:475)
at play.mvc.ActionInvoker.invokeControllerMethod(ActionInvoker.java:470)
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:158)
at play.server.PlayHandler$NettyInvocation.execute(PlayHandler.java:220)
at play.Invoker$Invocation.run(Invoker.java:265)
at play.server.PlayHandler$NettyInvocation.run(PlayHandler.java:200)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:98)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:206)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)

My Play! version: 1.2.2RC1
My Scala-Play: 0.9.1

--
Brian L. Troutwine

Sadek Drobi

unread,
Jun 6, 2011, 9:13:33 AM6/6/11
to play-fr...@googlegroups.com
The error is pretty clear. You need to use Long instead.

Brian Troutwine

unread,
Jun 6, 2011, 9:19:26 AM6/6/11
to play-fr...@googlegroups.com
On Mon, Jun 6, 2011 at 9:13 AM, Sadek Drobi <sadek...@gmail.com> wrote:
> The error is pretty clear. You need to use Long instead.

Ah, more to the point, why is this a runtime error and not a
compilation error is Play is to be more strict in numeric casting than
Scala? See that:

scala> val twoL:Long = 2
twoL: Long = 2

scala> val twoI:Int = 2
twoI: Int = 2

scala> twoL == twoI
res1: Boolean = true

Brian Troutwine

unread,
Jun 6, 2011, 9:29:09 AM6/6/11
to play-fr...@googlegroups.com
On Mon, Jun 6, 2011 at 9:19 AM, Brian Troutwine <br...@troutwine.us> wrote:
> On Mon, Jun 6, 2011 at 9:13 AM, Sadek Drobi <sadek...@gmail.com> wrote:
>> The error is pretty clear. You need to use Long instead.
>
> Ah, more to the point, why is this a runtime error and not a
> compilation error is Play is to be more strict in numeric casting than
> Scala? See that:
>
>    scala> val twoL:Long = 2
>    twoL: Long = 2
>
>    scala> val twoI:Int = 2
>    twoI: Int = 2
>
>    scala> twoL == twoI
>    res1: Boolean = true
>

(Sorry, bungled the sending of my last email.)

I think it's clear that I can avoid the error by requesting Longs
instead, but that I have to when I've requested a scalar[Int] and had
this code compile seems to indicate more a bug in Anorm than in my
thinking, no?

--
Brian L. Troutwine

Sadek Drobi

unread,
Jun 6, 2011, 10:03:33 AM6/6/11
to play-fr...@googlegroups.com
It is not a bug. It is the nature of parsers combinators: You expect things in some way and if they don't happen that way the parser fails. Database is not a part of your application, is a separate system and it can change at runtime.

Brian Troutwine

unread,
Jun 6, 2011, 11:22:11 AM6/6/11
to play-fr...@googlegroups.com
On Mon, Jun 6, 2011 at 10:03 AM, Sadek Drobi <sadek...@gmail.com> wrote:
> It is not a bug. It is the nature of parsers combinators: You expect things
> in some way and if they don't happen that way the parser fails. Database is
> not a part of your application, is a separate system and it can change at
> runtime.

That the database interaction is impure is orthogonal to an issue of
types: Play is missing out on the ability to make a valid, implicit
conversion. Clearly if I had issued scalar[String] I would deserve my
runtime exception. Not so, I assert, with scalar[Int] on a Long
return. If we look at scalar:

https://github.com/playframework/play-scala/blob/master/src/play/db/anorm/Anorm.scala#L315

You'll note that at #L321 it makes the correct conversation. The use
of Manifest >:> #L320 is the problem: Manifest[Int] is _isomorphic_ to
Manifest[Long] as Long is convertible to Int. It would be better to
define this function:

def orthoganol[S,T](l:Manifest[S], r:Manifest[T]):Boolean = {
try {
l.erasure.asInstanceOf[T]
true
} catch {
case e:java.lang.ClassCastException => false
}
}

And change #L321 to read

if ( orthoganol(m, TypeWrangler.javaType(a.asInstanceOf[AnyRef].getClass) ))

so that the full capability of asInstanceOf were made available.
Renaming 'orthoganol' as an infix '>%>' on ClassManifest would look
rather nicer.

Sadek Drobi

unread,
Jun 6, 2011, 11:31:44 AM6/6/11
to play-fr...@googlegroups.com
Converting a long to int is not valid and especially unsafe.

Brian Troutwine

unread,
Jun 6, 2011, 12:51:18 PM6/6/11
to play-fr...@googlegroups.com
On Mon, Jun 6, 2011 at 11:31 AM, Sadek Drobi <sadek...@gmail.com> wrote:
> Converting a long to int is not valid and especially unsafe.

The widths are wrong, yes, but I think that's beside the issue: Play
is missing the opportunity to make type conversions requested by the
user. Maybe I know my database better than you and the width of the
returned Long will always fit inside of an Int, which I want to
express as a type. If your aim is to restrict conversions in which
information might be lost, doing so implicitly is not the best way to
do so. Or consider if I were using my PhoneNumber library[1] to
convert strings that I knew were valid US phone numbers into
us.troutwine.phonenumber.USPhoneNumber instances. This latter fails
because of the use of asInstanceOf: though an implicit casts exists
between String and USPhoneNumber scala's runtime system is
side-stepped and cannot make the valid conversion. To use Scala's
conversion ability #L321 should be changed to

Right(a:T)

unless I am much mistaken.

[1] https://github.com/blt/PhoneNumber

Sadek Drobi

unread,
Jun 6, 2011, 1:23:08 PM6/6/11
to play-fr...@googlegroups.com
On Mon, Jun 6, 2011 at 6:51 PM, Brian Troutwine <br...@troutwine.us> wrote:
On Mon, Jun 6, 2011 at 11:31 AM, Sadek Drobi <sadek...@gmail.com> wrote:
> Converting a long to int is not valid and especially unsafe.

The widths are wrong, yes, but I think that's beside the issue: Play
is missing the opportunity to make type conversions requested by the
user. Maybe I know my database better than you and the width of the
returned Long will always fit inside of an Int, which I want to
express as a type. If your aim is to restrict conversions in which
information might be lost, doing so implicitly is not the best way to
do so. Or consider if I were using my PhoneNumber library[1] to
convert strings that I knew were valid US phone numbers into
us.troutwine.phonenumber.USPhoneNumber instances. This latter fails
because of the use of asInstanceOf: though an implicit casts exists
between String and USPhoneNumber scala's runtime system is
side-stepped and cannot make the valid conversion. To use Scala's
conversion ability #L321 should be changed to

   Right(a:T)

unless I am much mistaken.

Well you are. One thing you want to make sure as an API designer is to disallow silent bugs to sneak. The way you describe might work for you, but might create a runtime bug that is really hard to find.
In your case, you can simply use something like:

 def count(jid:String):Int = SQL(
   """
   select count(abu.created)
   from ActiveBridgeUser as abu
     join PlatonicBridgeUser as pbu on abu.pUserId=pbu.id
   where pbu.jid={jid}
   """
   ).on("jid" -> jid).as(scalar[Int] ^^ (_.toInt)) //same as scalar[Int].map(_.toInt)

If you think that scala is for implicitly converting between Long and Int then you really are wrong. Imagine things work as you described, at some point your long will grow bigger than an int and then you application will suddenly start acting weirdly after few years of deployment maybe.

Sadek

--
www.sadekdrobi.com
ʎdoɹʇuǝ

Brian Troutwine

unread,
Jun 6, 2011, 1:54:56 PM6/6/11
to play-fr...@googlegroups.com

I cede that converting a Long to a less wide type can cause problems:
I did not contest this. You will also note that I specifically defined
the overflow problem as nil: without Dependent Typing Scala users must
known the range of numeric values to be converted. I defined a
hypothetical in which the conversion is valid, in which scalar
incorrectly restricts my knowledgeable action as a user; this was
ignored. My contention is that scalar is unable to make valid
conversions _requested by the user_. I further illustrated this with a
String to USPhoneNumber conversion: you ignored this. In it's current
state Anorm catches some bugs _only incidentally_. This is a
misfeature in that Anorm refuses to make valid conversions. That
Long->Int is possible at runtime and performs no value checking is a
historical curiosity and beside my point. (If Anorm _really_ were
written with runtime width safety in mind it would not return the
finite Long but, rather, scala.math.BigInt. You will note that _this_
conversion is also not possible with scalar. I digress.)

I will enumerate again:

* Anorm's scalar breaks type parameter semantics by failing to make
valid conversions from the underlying type.
* That scalar is unable to make some invalid numeric conversions is
not a feature.
* The Scala type system lacks dependent types: scalar is
accidentally disallowing some conversions that a dependent types would
fix.

Finally, if I have to perform an explicit conversion on the return
from scalar I must know what types scalar _will_ return from the
underlying database connection. As there is no restriction on the T
accepted by scalar I must discover this accidentally: the type-system
is subverted by allowing a general T at compile-time when the authors
had a more restricted type S in mind. Consistent with my semantics
violation assertion, why even bother with scalar? If I _know_ that all
strings coming out of a query will be valid USPhoneNumbers, what sense
does it make to do scalar[String].map(s => new USPhoneNumber(s)), say?

> Sadek

Brian Troutwine

unread,
Jun 6, 2011, 3:33:32 PM6/6/11
to play-fr...@googlegroups.com
On Mon, Jun 6, 2011 at 3:04 PM, Sadek Drobi <sadek...@gmail.com> wrote:
>>
>>
>> I cede that converting a Long to a less wide type can cause problems:
>
> It was confusing as an argument.

>
>>
>> I did not contest this. You will also note that I specifically defined
>> the overflow problem as nil: without Dependent Typing Scala users must
>> known the range of numeric values to be converted. I defined a
>> hypothetical in which the conversion is valid, in which scalar
>> incorrectly restricts my knowledgeable action as a user; this was
>> ignored. My contention is that scalar is unable to make valid
>> conversions _requested by the user_. I further illustrated this with a
>> String to USPhoneNumber conversion: you ignored this.
>
> You are right, I was arguing having in mind ColumnTo together with other
> extensible parsers (like get). scalar is not extensible in the same way and
> certainly should improve. It should rather integrate a mechanism similar to
> ColumnTo that would allow you to extend to read things your way. Take a look
> at get parser and you'll see what I mean.

ColumnTo? The only documentation I have is here:

http://scala.playframework.org/documentation/scala-0.9.1/anorm#UsingtheParsercombinatorAPI

ColumnTo is not mentioned there, I'm afraid.

>>
>> In it's current
>> state Anorm catches some bugs _only incidentally_. This is a
>> misfeature in that Anorm refuses to make valid conversions. That
>> Long->Int is possible at runtime and performs no value checking is a
>> historical curiosity and beside my point. (If Anorm _really_ were
>> written with runtime width safety in mind it would not return the
>> finite Long but, rather, scala.math.BigInt. You will note that _this_
>> conversion is also not possible with scalar. I digress.)
>>
>

> I don't agree. Even if I agree about scalar, other parsers are very
> extensible and you can easily adapt them to your own types. If there is a
> thing that can be improved then it should be an access to lower level
> resultset without passing and being constrained by JDBC cooked up
> ResultSetMetaData. That is certainly a place I am willing to improve.

Perhaps part of our communication problem is that, given the
documentation available, I do not know what scalar is _intended_ to
do. Reading the source code I have an idea of what it does, but that's
not always a clear way to get at the author's hopes. Especially when
the source code is not commented.

>>
>> I will enumerate again:
>>
>>   * Anorm's scalar breaks type parameter semantics by failing to make
>> valid conversions from the underlying type.
>

> Again, that is the case of scalar but not any of the other parsers.

This must be an issue of documentation. What is the aim of scalar?
From it's name I assume it holds only a single type, but to what end I
do not know.

>>
>>   * That scalar is unable to make some invalid numeric conversions is
>> not a feature.
>

> Correct, I will fix it and it will have a default behavior not to do invalid
> conversion and you can override that then exactly like now for 'get' Parser.

The get parser? Also, how will you define valid and invalid conversions?

>>
>>   * The Scala type system lacks dependent types: scalar is
>> accidentally disallowing some conversions that a dependent types would
>> fix.
>>

> I doubt dependent types would save anything here. If one execution of the
> query returns a 'correct' Int doesn't mean the category of the result is
> Int.

Sure it would. Force scalar to produce the widest dependent numerical
type internally, have the compiler complain if the user attempts to
cast to a less-wide type. Or, alternatively, issue a runtime error on
implicit conversion if the less-wide type will not contain the value:
clearer error message, you maintain the current runtime checking and
you paper over the defects in Java's numeric type hierarchy.

>>
>> Finally, if I have to perform an explicit conversion on the return
>> from scalar I must know what types scalar _will_ return from the
>> underlying database connection. As there is no restriction on the T
>> accepted by scalar I must discover this accidentally: the type-system
>> is subverted by allowing a general T at compile-time when the authors
>> had a more restricted type S in mind. Consistent with my semantics
>> violation assertion, why even bother with scalar? If I _know_ that all
>> strings coming out of a query will be valid USPhoneNumbers, what sense
>> does it make to do scalar[String].map(s => new USPhoneNumber(s)), say?
>

> Again the problem with scalar. 'get' puts a restriction on allowed T which
> is the implementation of ColumnTo[T]

I see neither 'get' nor ColumnTo in the available documentation.
Additionally, it seems that no API reference is available.

> Sadek

Sadek Drobi

unread,
Jun 6, 2011, 3:04:46 PM6/6/11
to play-fr...@googlegroups.com


I cede that converting a Long to a less wide type can cause problems:

It was confusing as an argument.
 
I did not contest this. You will also note that I specifically defined

the overflow problem as nil: without Dependent Typing Scala users must
known the range of numeric values to be converted. I defined a
hypothetical in which the conversion is valid, in which scalar
incorrectly restricts my knowledgeable action as a user; this was
ignored. My contention is that scalar is unable to make valid
conversions _requested by the user_. I further illustrated this with a
String to USPhoneNumber conversion: you ignored this.
You are right, I was arguing having in mind ColumnTo together with other extensible parsers (like get). scalar is not extensible in the same way and certainly should improve. It should rather integrate a mechanism similar to ColumnTo that would allow you to extend to read things your way. Take a look at get parser and you'll see what I mean.

 
In it's current

state Anorm catches some bugs _only incidentally_. This is a
misfeature in that Anorm refuses to make valid conversions. That
Long->Int is possible at runtime and performs no value checking is a
historical curiosity and beside my point. (If Anorm _really_ were
written with runtime width safety in mind it would not return the
finite Long but, rather, scala.math.BigInt. You will note that _this_
conversion is also not possible with scalar. I digress.)


I don't agree. Even if I agree about scalar, other parsers are very extensible and you can easily adapt them to your own types. If there is a thing that can be improved then it should be an access to lower level resultset without passing and being constrained by JDBC cooked up ResultSetMetaData. That is certainly a place I am willing to improve.
 
I will enumerate again:


  * Anorm's scalar breaks type parameter semantics by failing to make
valid conversions from the underlying type.
Again, that is the case of scalar but not any of the other parsers.
 
  * That scalar is unable to make some invalid numeric conversions is
not a feature.

Correct, I will fix it and it will have a default behavior not to do invalid conversion and you can override that then exactly like now for 'get' Parser.
 
  * The Scala type system lacks dependent types: scalar is

accidentally disallowing some conversions that a dependent types would
fix.

I doubt dependent types would save anything here. If one execution of the query returns a 'correct' Int doesn't mean the category of the result is Int.

 
Finally, if I have to perform an explicit conversion on the return

from scalar I must know what types scalar _will_ return from the
underlying database connection. As there is no restriction on the T
accepted by scalar I must discover this accidentally: the type-system
is subverted by allowing a general T at compile-time when the authors
had a more restricted type S in mind. Consistent with my semantics
violation assertion, why even bother with scalar? If I _know_ that all
strings coming out of a query will be valid USPhoneNumbers, what sense
does it make to do scalar[String].map(s => new USPhoneNumber(s)), say?
Again the problem with scalar. 'get' puts a restriction on allowed T which is the implementation of ColumnTo[T]

Sadek
 

> Sadek
> --
> www.sadekdrobi.com
> ʎdoɹʇuǝ
>
> --
> You received this message because you are subscribed to the Google Groups
> "play-framework" group.
> To post to this group, send email to play-fr...@googlegroups.com.
> To unsubscribe from this group, send email to
> play-framewor...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/play-framework?hl=en.
>



--
Brian L. Troutwine

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.




--
www.sadekdrobi.com
ʎdoɹʇuǝ

Sadek Drobi

unread,
Jun 6, 2011, 3:48:55 PM6/6/11
to play-fr...@googlegroups.com
On Mon, Jun 6, 2011 at 9:33 PM, Brian Troutwine <br...@troutwine.us> wrote:
On Mon, Jun 6, 2011 at 3:04 PM, Sadek Drobi <sadek...@gmail.com> wrote:
>>
>>
>> I cede that converting a Long to a less wide type can cause problems:
>
> It was confusing as an argument.
>
>>
>> I did not contest this. You will also note that I specifically defined
>> the overflow problem as nil: without Dependent Typing Scala users must
>> known the range of numeric values to be converted. I defined a
>> hypothetical in which the conversion is valid, in which scalar
>> incorrectly restricts my knowledgeable action as a user; this was
>> ignored. My contention is that scalar is unable to make valid
>> conversions _requested by the user_. I further illustrated this with a
>> String to USPhoneNumber conversion: you ignored this.
>
> You are right, I was arguing having in mind ColumnTo together with other
> extensible parsers (like get). scalar is not extensible in the same way and
> certainly should improve. It should rather integrate a mechanism similar to
> ColumnTo that would allow you to extend to read things your way. Take a look
> at get parser and you'll see what I mean.

ColumnTo? The only documentation I have is here:

   http://scala.playframework.org/documentation/scala-0.9.1/anorm#UsingtheParsercombinatorAPI

ColumnTo is not mentioned there, I'm afraid.

val populations:List[String~Int] = { SQL("select * from Country").as( get[String]("name") ~< get[Int]("population") * ) }

This is from documentation you references. "get" will look for a ColumnTo implementation in the scope of the same desired type. "scalar" means one column one line and you do not want to use column name for that. Again it should be improved not to use Manifest but something more useful.

 

>>
>> In it's current
>> state Anorm catches some bugs _only incidentally_. This is a
>> misfeature in that Anorm refuses to make valid conversions. That
>> Long->Int is possible at runtime and performs no value checking is a
>> historical curiosity and beside my point. (If Anorm _really_ were
>> written with runtime width safety in mind it would not return the
>> finite Long but, rather, scala.math.BigInt. You will note that _this_
>> conversion is also not possible with scalar. I digress.)
>>
>
> I don't agree. Even if I agree about scalar, other parsers are very
> extensible and you can easily adapt them to your own types. If there is a
> thing that can be improved then it should be an access to lower level
> resultset without passing and being constrained by JDBC cooked up
> ResultSetMetaData. That is certainly a place I am willing to improve.

Perhaps part of our communication problem is that, given the
documentation available, I do not know what scalar is _intended_ to
do. Reading the source code I have an idea of what it does, but that's
not always a clear way to get at the author's hopes. Especially when
the source code is not commented.

"scalar" represents a single returned value. And it needs to be improved but it works for now for things like count. Otherwise use get

val populations:List[String~Int] = { SQL("select * from Country").as( get[String]("name") ~< get[Int]("population") * ) }
We have to improve regarding documentation. But get is there

val populations:List[String~Int] = { SQL("select * from Country").as( get[String]("name") ~< get[Int]("population") * ) }
 
And ColumnTo is an extension mechanism for supporting custom types.



--
www.sadekdrobi.com
ʎdoɹʇuǝ
Reply all
Reply to author
Forward
0 new messages