Dynamic mixin in Scala - is it possible? -
what i'd achieve having proper implementation for
def dynamix[a, b](a: a): b
i may know b is, don't know (but if b has self type add constraints on a). scala compiler happy above signature, not yet figure out how implementation - if possible @ all.
some options came mind:
- using reflection/dynamic proxy.
- simplest case: interface on java level + can instantiate b , has no self type. guess not hard (unless run nasty, unexpected problems):
create new b (b), , proxy implementing both , b , using invocation handler delegating either or b. - if b can not instantiated still create subclass of it, , described above. if has self type need delegation here , there, may still work.
- but if concrete type , can't find proper interface it?
- would run more problems (e.g. related linearization, or special constructs helping java interoperability)?
- simplest case: interface on java level + can instantiate b , has no self type. guess not hard (unless run nasty, unexpected problems):
- using kind of wrapping instead of mixin , return b[a], accessible b.
unfortunately in case caller need know how nesting done, quite inconvenient if mixing in/wrapping done several times (d[c[b[a]]]) need find right level of nesting access needed functionality, don't consider solution. - implementing compiler plugin. have 0 experience gut feeling not trivial. think kevin wright's autoproxy plugin has bit similar goal, not enough problem (yet?).
do have other ideas might work? way recommend? kind of "challenges" expect?
or should forget it, because not possible current scala constraints?
intention behind problem: have business workflow, it's not strict. steps have fixed order, others not, @ end of them has done (or of them required further processing).
bit more concrete example: have a, can add b , c it. don't care done first, @ end i'll need b c.
comment: don't know groovy popped this question , guess it's more or less same i'd like, @ least conceptional.
i believe impossible strictly @ runtime, because traits mixed in @ compile-time new java classes. if mix trait existing class anonymously can see, looking @ classfiles , using javap, anonymous, name-mangled class created scalac:
class foo { def bar = 5 } trait spam { def eggs = 10 } object main { def main(args: array[string]) = { println((new foo spam).eggs) } }
scalac mixin.scala; ls *.class
returns
foo.class main$.class spam$class.class main$$anon$1.class main.class spam.class
while javap main\$\$anon\$1
returns
compiled "mixin.scala" public final class main$$anon$1 extends foo implements spam{ public int eggs(); public main$$anon$1(); }
as can see, scalac creates new anonymous class loaded @ runtime; presumably method eggs
in anonymous class creates instance of spam$class
, calls eggs
on it, i'm not sure.
however, can pretty hacky trick here:
import scala.tools.nsc._; import scala.reflect.manifest object dynamicclassloader { private var id = 0 def uniqueid = synchronized { id += 1; "klass" + id.tostring } } class dynamicclassloader extends java.lang.classloader(getclass.getclassloader) { def buildclass[t, v](implicit t: manifest[t], v: manifest[v]) = { // create unique id val id = dynamicclassloader.uniqueid // what's scala code need generate class? val classdef = "class %s extends %s %s". format(id, t.tostring, v.tostring) println(classdef) // fire new scala interpreter/compiler val settings = new settings(null) val interpreter = new interpreter(settings) // define class interpreter.compileandsaverun("<anon>", classdef) // bytecode new class val bytes = interpreter.classloader.getbytesforclass(id) // define bytecode using classloader; cast expect defineclass(id, bytes, 0, bytes.length).asinstanceof[class[t v]] } } val loader = new dynamicclassloader val instance = loader.buildclass[foo, spam].newinstance instance.bar // int = 5 instance.eggs // int = 10
since need use scala compiler, afaik, close cleanest solution this. it's quite slow, memoization greatly.
this approach pretty ridiculous, hacky, , goes against grain of language. imagine sorts of weirdo bugs creep in; people have used java longer me warn of insanity comes messing around classloaders.
Comments
Post a Comment