can not bind generics

13 views
Skip to first unread message

Илья Фивейский

unread,
Feb 9, 2012, 10:00:29 AM2/9/12
to sindi...@googlegroups.com
Hello.

Code 

package scala1

import sindi._

class Class1[A]
class Class2(c: Class1[String])

object AppContext extends Context {
  override val bindings = Bindings(
 bind[Class1[String]] to new Class1[String]
      )
val c = autowire[Class2]
}

object Main{
  def main(args: Array[String]){
println(AppContext.c)
  }
}


throws run-time error "sindi.exception.TypeNotBoundException: Unable to inject scala1.Class2 during autowiring: type is not bound."
Without A parameter (i.e. when Class1 is not generic) it works fine.
Am I missing something?

Full error log:

[info] Running scala1.Main 
[error] (run-main) java.lang.ExceptionInInitializerError
java.lang.ExceptionInInitializerError
at scala1.Main$.main(Main.scala:17)
at scala1.Main.main(Main.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
Caused by: sindi.exception.TypeNotBoundException: Unable to inject scala1.Class2 during autowiring: type is not bound.
at sindi.context.Wirable$$anonfun$wireFirst$1.apply(context.scala:96)
at sindi.context.Wirable$$anonfun$wireFirst$1.apply(context.scala:96)
at scala.Option.getOrElse(Option.scala:108)
at sindi.context.Wirable$class.wireFirst(context.scala:95)
at sindi.context.Wirable$class.autowire(context.scala:76)
at scala1.AppContext$.autowire(Main.scala:8)
at scala1.AppContext$.<init>(Main.scala:12)
at scala1.AppContext$.<clinit>(Main.scala)
at scala1.Main$.main(Main.scala:17)
at scala1.Main.main(Main.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
java.lang.RuntimeException: Nonzero exit code: 1
at scala.sys.package$.error(package.scala:27)


Alois Cochard

unread,
Feb 9, 2012, 2:42:48 PM2/9/12
to sindi-users
Hello,

You are not missing something!

It's because the experimental 'autowire' feature isn't actually
implemented on the compiler plugin side, and you are actually facing
type erasure limitation.
I'm plan to release full autowire support in release 0.5, and actually
clearly focusing on improving compiler support and adding more sugar.

In the mean time you can achieve want you want with manual wiring:

object AppContext extends Context {
override val bindings = Bindings(bind[Class1[String]] to new
Class1[String])
val c = new Class2(inject[Class1[String]])
}

Basically the integration of autowiring in compiler plugin will
rewrite autowire calls to manual wiring by analyzing AST, the second
main feature will be to automatically export module bindings. Theses
new features will remove all the boilerplate code which is actually
needed.

Thanks a lot for your feedback, and sorry that are you facing such
limitation of the experimental autowiring feature!

PS: You can too be interested by taking a look at the ModuleT feature
which is unfortunately not documented yet, but you can see an example
here:
https://github.com/aloiscochard/sindi/blob/master/sindi-examples/demo/src/main/scala/store/StoreModule.scala

Alois Cochard

Alois Cochard

unread,
Feb 15, 2012, 9:25:45 AM2/15/12
to sindi-users
Hello,

After having doing some more implementation of autowiring during the
weekend on 0.5-SNAPSHOT, I decided to drop "class" or "type"
autowiring in favor of function autowiring (it mean autowire[T] will
be removed in next release).

In 0.4, only Function1 and Function2 are supported but I just added
the boilerplate in 0.5-SNAPSHOT up to Function22.

And by doing function autowiring on class constructor, this solve your
issue!

Here is how:
val c = autowire(new Class2(_: Class1[String]))

Unfortunatly due to some limitation in Scala type inferance you need
to specify "Class1[String]" explicity, but it's not the case with a
Companion object:

object Class2 { def apply(c: Class1[String]) = new Class2(c) }

Then you can do:
val c = autowire(Class2(_))

Neat!!

As a side note I would recommend avoiding instanciating class directly
and prefer the usage of Companion as much as possible.

Cheers,

On Feb 9, 4:00 pm, Илья Фивейский <ilya.f...@gmail.com> wrote:
> >> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImp l.java:43)
>
> >  at java.lang.reflect.Method.invoke(Method.java:616)
>
> > Caused by: sindi.exception.TypeNotBoundException: Unable to inject
> >> scala1.Class2 during autowiring: type is not bound.
>
> >  at sindi.context.Wirable$$anonfun$wireFirst$1.apply(context.scala:96)
>
> >  at sindi.context.Wirable$$anonfun$wireFirst$1.apply(context.scala:96)
>
> >  at scala.Option.getOrElse(Option.scala:108)
>
> >  at sindi.context.Wirable$class.wireFirst(context.scala:95)
>
> >  at sindi.context.Wirable$class.autowire(context.scala:76)
>
> >  at scala1.AppContext$.autowire(Main.scala:8)
>
> >  at scala1.AppContext$.<init>(Main.scala:12)
>
> >  at scala1.AppContext$.<clinit>(Main.scala)
>
> >  at scala1.Main$.main(Main.scala:17)
>
> >  at scala1.Main.main(Main.scala)
>
> >  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>
> >  at
> >> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:5 7)
>
> >  at
> >> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImp l.java:43)

Илья Фивейский

unread,
Feb 16, 2012, 3:53:17 PM2/16/12
to sindi...@googlegroups.com
With companion object in 

val c = autowire(Class2(_))

I get error

[error] /home/ilya/Data/workspace/Scala1/src/main/scala/Main.scala:14: missing parameter type for expanded function ((x$1) => Class2(x$1))
[error] val c = autowire(Class2(_))
[error]                        ^

If I change it to

val c = autowire(Class2(_: Class1[String]))

then code compiles.

2012/2/15 Alois Cochard <alois....@gmail.com>

Alois Cochard

unread,
Feb 16, 2012, 5:16:52 PM2/16/12
to sindi...@googlegroups.com
Yeah sorry, I did wrong assumption about scala type inference capability :-(

I just re-factored function autowiring to return, R instead of => R, this greatly ease it usage.
I think implementation of autowiring is complete now and shouldn't change before 0.5 release.

This now work that way (with Companion):
val c = autowire(Class2.apply _)

I just pushed right now an other 0.5-SNAPSHOT version with the autowiring refactoring, not sure if SBT will update it without cleaning ~/.ivy2/cache/com.github.aloiscochard.sindi.* manually.

Tell me if you run into any issue getting the last SNAPSHOT.

Cheers,

PS: It was already working with other version but when you do autowire(Class.apply _) it was returning a "() => Class" which isn't very handy, it's why I preferred changing it that way.

2012/2/16 Илья Фивейский <ilya...@gmail.com>



--
Alois Cochard

Alois Cochard

unread,
Feb 16, 2012, 5:19:45 PM2/16/12
to sindi...@googlegroups.com
After updating could be worth doing a 'sbt clean' before recompiling your project.

Looking forward your feedback!

Thanks,

2012/2/16 Alois Cochard <alois....@gmail.com>
Reply all
Reply to author
Forward
0 new messages