[Lift] Re: Help with writing generic functions for lift mapper

2009-06-19 Thread David Pollak
On Fri, Jun 19, 2009 at 6:35 AM, Sean Reque seanre...@gmail.com wrote:


 I am trying to write a generic function to do a on-to-one join between
 mapper objects in memory using a map. The function is as follows:

  def oneToOneJoin[PType : LongKeyedMapper[PType] with IdPK,
   CType : LongKeyedMapper[CType] with IdPK,
   CMetaType : CType with LongKeyedMetaMapper
 [CType],
   FKType : MappedLongForeignKey[PType, CType]]
  (parents: List[PType], metaMapper: CMetaType, keyGetter: (PType) =
 FKType ):
  Map[Long, CType] = {
(Map.empty[Long, CType] /: metaMapper.findAll(
  ByList(metaMapper.id, parents.map {p = keyGetter
 (p).is.longValue } ))
  ) {(accum, v) = accum + (v.id.longValue - v) }

 This function compiles fine, but I can't use it! Here is the call
 site:

 Util.oneToOneJoin(runs, TestSubject, (tr: TestRun) = tr.testSubject

  where runs is of type List[TestRun]

 Here are the relevant class and object definitions. All the
 definitions are by the book, meaning the exploring Lift book :).
 Each test run has one test subject.

  class TestSubject extends LongKeyedMapper[TestSubject] with IdPK {
  object TestSubject extends TestSubject with LongKeyedMetaMapper
 [TestSubject] {
  class TestRun extends LongKeyedMapper[TestRun] with IdPK {
  object testSubject extends MappedLongForeignKey(this,
 TestSubject)
   }
  object TestRun extends TestRun with LongKeyedMetaMapper[TestRun]
 with CRUDify[Long, TestRun] {




 I get an error that makes me think I'm coding in C++ with the boost
 library. Scala is inferring CType as Nothing, which is definitely not
 what I want.

 error: inferred type arguments
 [com.test_results.model.TestRun,Nothing,object
 com.test_results.model.TestSubject,object
 com.test_results.model.TestRun#testSubject] do not conform to method
 oneToOneJoin's type parameter bounds [PType :
 net.liftweb.mapper.LongKeyedMapper[PType] with
 net.liftweb.mapper.IdPK,CType : net.liftweb.mapper.LongKeyedMapper
 [CType] with net.liftweb.mapper.IdPK,CMetaType : CType with
 net.liftweb.mapper.LongKeyedMetaMapper[CType],FKType :
 net.liftweb.mapper.MappedLongForeignKey[PType,CType]]
Util.oneToOneJoin(runs, TestSubject, (tr: TestRun) =
 tr.testSubject)

 I cannot find any way to get the class of the TestSubject companion
 object, So I changed things slightly to create a MetaTestSubject and
 then tried to explicitly specify the type parameters to the
 oneToOneJoin function as shown below. MetaTestSubject is the supertype
 for the TestSubject companion object so that I can reference it's type
 explicitly.

  Util.oneToOneJoin[TestRun,
TestSubject,
MetaTestSubject,
(TestRun) = MappedLongForeignKey[TestRun,
 TestSubject]
  ](runs, TestSubject, (tr: TestRun) = tr.testSubject)

  where MetaTestSubject and TestSubject are now defined as
class MetaTestSubject extends TestSubject with LongKeyedMetaMapper
 [TestSubject]
object TestSubject extends MetaTestSubject {


 When I specify the types to the oneToOneJoin function explicitly,
 Scala then just plain tells me that the types don't match with this
 error.

  error: type arguments

 [com.test_results.model.TestRun,com.test_results.model.TestSubject,com.test_results.model.MetaTestSubject,
 (com.test_results.model.TestRun) =
 net.liftweb.mapper.MappedLongForeignKey
 [com.test_results.model.TestRun,com.test_results.model.TestSubject]]
 do not conform to method oneToOneJoin's type parameter bounds [PType
 : net.liftweb.mapper.LongKeyedMapper[PType] with
 net.liftweb.mapper.IdPK,CType : net.liftweb.mapper.LongKeyedMapper
 [CType] with net.liftweb.mapper.IdPK,CMetaType : CType with
 net.liftweb.mapper.LongKeyedMetaMapper[CType],FKType :
 net.liftweb.mapper.MappedLongForeignKey[PType,CType]]
  Util.oneToOneJoin[TestRun,

 After a couple of hours of trying I am stuck at this point and all of
 the types look like they line up to me. TestRun is a LongKeyedMapper
 of the right type with IdPK, and so is TestSubject. MetaTestSubject
 inherits from TestSubject with LongKeyedMetaMapper[TestSubject]. The
 third value parameter is a function takes a type TestRun and returns a
 MappedLongForeignKey[TestRun, TestSubject].

 What am I doing wrong?


In the second one where you explicitly specified the types, you are doing
nothing wrong.

In the first case, because there were no parameters with the type CType, the
type inferencer couldn't figure out what CType was.  The type inferencer
only looks a certain number of levels for a type in order to avoid cyclical
type references and in order to save compilation speed.


 Is this a scala bug?


Yes.

I would suggest reporting it.



 - Sean Reque

 



-- 
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp

--~--~-~--~~~---~--~~

[Lift] Re: Help with writing generic functions for lift mapper

2009-06-19 Thread Sean Reque

Thanks for the quick response! I will submit a ticket in the scala bug
tracker.

On Jun 19, 10:14 am, David Pollak feeder.of.the.be...@gmail.com
wrote:
 On Fri, Jun 19, 2009 at 6:35 AM, Sean Reque seanre...@gmail.com wrote:

  I am trying to write a generic function to do a on-to-one join between
  mapper objects in memory using a map. The function is as follows:

   def oneToOneJoin[PType : LongKeyedMapper[PType] with IdPK,
                    CType : LongKeyedMapper[CType] with IdPK,
                    CMetaType : CType with LongKeyedMetaMapper
  [CType],
                    FKType : MappedLongForeignKey[PType, CType]]
   (parents: List[PType], metaMapper: CMetaType, keyGetter: (PType) =
  FKType ):
   Map[Long, CType] = {
     (Map.empty[Long, CType] /: metaMapper.findAll(
           ByList(metaMapper.id, parents.map {p = keyGetter
  (p).is.longValue } ))
           ) {(accum, v) = accum + (v.id.longValue - v) }

  This function compiles fine, but I can't use it! Here is the call
  site:

  Util.oneToOneJoin(runs, TestSubject, (tr: TestRun) = tr.testSubject

   where runs is of type List[TestRun]

  Here are the relevant class and object definitions. All the
  definitions are by the book, meaning the exploring Lift book :).
  Each test run has one test subject.

   class TestSubject extends LongKeyedMapper[TestSubject] with IdPK {
   object TestSubject extends TestSubject with LongKeyedMetaMapper
  [TestSubject] {
   class TestRun extends LongKeyedMapper[TestRun] with IdPK {
       object testSubject extends MappedLongForeignKey(this,
  TestSubject)
    }
   object TestRun extends TestRun with LongKeyedMetaMapper[TestRun]
  with CRUDify[Long, TestRun] {

  I get an error that makes me think I'm coding in C++ with the boost
  library. Scala is inferring CType as Nothing, which is definitely not
  what I want.

  error: inferred type arguments
  [com.test_results.model.TestRun,Nothing,object
  com.test_results.model.TestSubject,object
  com.test_results.model.TestRun#testSubject] do not conform to method
  oneToOneJoin's type parameter bounds [PType :
  net.liftweb.mapper.LongKeyedMapper[PType] with
  net.liftweb.mapper.IdPK,CType : net.liftweb.mapper.LongKeyedMapper
  [CType] with net.liftweb.mapper.IdPK,CMetaType : CType with
  net.liftweb.mapper.LongKeyedMetaMapper[CType],FKType :
  net.liftweb.mapper.MappedLongForeignKey[PType,CType]]
     Util.oneToOneJoin(runs, TestSubject, (tr: TestRun) =
  tr.testSubject)

  I cannot find any way to get the class of the TestSubject companion
  object, So I changed things slightly to create a MetaTestSubject and
  then tried to explicitly specify the type parameters to the
  oneToOneJoin function as shown below. MetaTestSubject is the supertype
  for the TestSubject companion object so that I can reference it's type
  explicitly.

   Util.oneToOneJoin[TestRun,
                     TestSubject,
                     MetaTestSubject,
                     (TestRun) = MappedLongForeignKey[TestRun,
  TestSubject]
   ](runs, TestSubject, (tr: TestRun) = tr.testSubject)

   where MetaTestSubject and TestSubject are now defined as
     class MetaTestSubject extends TestSubject with LongKeyedMetaMapper
  [TestSubject]
     object TestSubject extends MetaTestSubject {

  When I specify the types to the oneToOneJoin function explicitly,
  Scala then just plain tells me that the types don't match with this
  error.

   error: type arguments

  [com.test_results.model.TestRun,com.test_results.model.TestSubject,com.test_results.model.MetaTestSubject,
  (com.test_results.model.TestRun) =
  net.liftweb.mapper.MappedLongForeignKey
  [com.test_results.model.TestRun,com.test_results.model.TestSubject]]
  do not conform to method oneToOneJoin's type parameter bounds [PType
  : net.liftweb.mapper.LongKeyedMapper[PType] with
  net.liftweb.mapper.IdPK,CType : net.liftweb.mapper.LongKeyedMapper
  [CType] with net.liftweb.mapper.IdPK,CMetaType : CType with
  net.liftweb.mapper.LongKeyedMetaMapper[CType],FKType :
  net.liftweb.mapper.MappedLongForeignKey[PType,CType]]
       Util.oneToOneJoin[TestRun,

  After a couple of hours of trying I am stuck at this point and all of
  the types look like they line up to me. TestRun is a LongKeyedMapper
  of the right type with IdPK, and so is TestSubject. MetaTestSubject
  inherits from TestSubject with LongKeyedMetaMapper[TestSubject]. The
  third value parameter is a function takes a type TestRun and returns a
  MappedLongForeignKey[TestRun, TestSubject].

  What am I doing wrong?

 In the second one where you explicitly specified the types, you are doing
 nothing wrong.

 In the first case, because there were no parameters with the type CType, the
 type inferencer couldn't figure out what CType was.  The type inferencer
 only looks a certain number of levels for a type in order to avoid cyclical
 type references and in order to save compilation speed.

  Is this a scala bug?

 Yes.

 I would suggest reporting it.



  - Sean Reque

 --
 Lift,