Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to import inner classes without path dependency in Scala?

TL&DR: Is it possible to (locally?) disable path-dependent typing? I'd like to issue a single import statement similar to import x._, but to make C refer to X#C rather than x.C (X being the type of x)?

I have a bunch of types:

class Button[M] { ... }
class Label[M] { ... }
...

And I happen to use them together passing the same type argument to all of them:

class UseSite[M] (
   btn1 : Button[M]
 , btn2 : Button[M]
 , lbl1 : Label[M]) {
  ...
}

I thought that it'd be nice to package all those types up so that I only need to pass the type parameter once:

class Swing[M] {
  class Button { ... }
  class Label { ...}
}

Then on the use site I'd like to be able to do this:

class WithSwing[M] {
  val swing = new Swing[M]
  import swing._
  class UseSite(
     btn1 : Button
   , btn2 : Button
   , lbl1 : Label) {
    ...
  }
}

However, this does not work properly because of path-dependent typing: Button refers to swing.Button instead of Swing[M]#Button so the external code has a very hard time passing the correct arguments to the UseSite constructor.

Is there a nice way to make Button refer to Swing[M]#Button rather than to swing.Button?

like image 681
Rotsor Avatar asked Jan 23 '12 00:01

Rotsor


1 Answers

Assuming that the path dependencies really are accidental, then rather than chase type projections all the way through your codebase, you could try something like this,

class Button[M]
class Label[M]

trait Swing[M] {
  type ButtonM = Button[M]
  type LabelM = Label[M]
}

class WithSwing[M] {
  val swing = new Swing[M] {}
  import swing._
  class UseSite(btn1 : ButtonM, btn2 : ButtonM, lbl1 : LabelM)
}

Outside WithSwing usage would look like,

val ws = new WithSwing[String]
import ws.swing._
new ws.UseSite(new ButtonM {}, new ButtonM {}, new LabelM {})

Inheritance increases brevity somewhat,

class WithSwing[M] extends Swing[M] {
  class UseSite(btn1 : ButtonM, btn2 : ButtonM, lbl1 : LabelM)
}

// Usage ...
val ws = new WithSwing[String]
import ws._
new ws.UseSite(new ButtonM {}, new ButtonM {}, new LabelM {})
like image 78
Miles Sabin Avatar answered Nov 15 '22 10:11

Miles Sabin