2

say I have the following code:

package my
class Foo 
class Bar extends Foo
object Chooser {
   val isFoo = true
} 

I import Foo as:

import my.{Foo => MyClass}

I want to be able to do something like:

If Chooser.isFoo, then:

import my.{Foo => MyClass}

else:

import my.{Bar => MyClass}

I have used Foo in my code as something like this:

object MyObj {
   val a = new MyClass
   // ...
}

Are there any hidden features of Scala that let me use Bar in place of Foo without modifying the code of MyObj at all. Also what would be the best way to design such code in future so that such extensions are easy?

Community
  • 1
  • 1
Jus12
  • 17,824
  • 28
  • 99
  • 157
  • 2
    An import happens at compile time. Your choice (based on Chooser.isFoo) happens at run time, after the import has happened. So what you're asking for can't work. Can you provide a facade that implemnents an API that works with both Foo and Bar libraries, write the rest of your code to that API. Then provide two implementations facade-for-Bar, bundled with the Bar libraries, facade-for-Foo, bundled with the Foo libraries? – The Archetypal Paul Nov 04 '14 at 15:55

2 Answers2

2

There isn't but I'm guessing you are more interested in different implementations at runtime than in conditional type import. Your Chooser.isFoo sounds like something that happens during runtime and not in the type system.

One example of how you could do it, since the common type for Foo and Bar is Foo:

val a: Foo = 
  if (Chooser.isFoo) new my.Foo
  else new my.Bar

Edit based on your edit: you could delay the choice by having an abstract type or a type parameter, like so:

class MyObj[T :> Foo] {
  val a: T
}

val anInstance = new MyObj[Foo]
val anotherInstance = new MyObj[Bar]

Note the type bound that says that T must be a subclass of Foo, or else you wouldn't know anything about what you can do with a T.

johanandren
  • 11,249
  • 1
  • 25
  • 30
  • Or just add a method to `Chooser` `def getObj = if (isFoo) new Foo else new Bar` and then have `MyObj` call that. That would free the `MyObj` class from needing to be aware of the subtypes of Foo. – Ian McLaird Nov 04 '14 at 15:44
  • I kind of need the conditional import because I am using certain libraries (needed by `Bar`) that can be used in one situation but cannot be used in another (due to license). If I use the chooser, then those libraries need to be provided even when `Bar` is not used, if I am not mistaken. – Jus12 Nov 04 '14 at 15:47
  • 1
    Even if it's a licensing issue, you're still just doing runtime feature detection. When you can, you distribute the libraries needed by `Bar`. At runtime, detect whether the library is present. If it is, return a `Bar`, otherwise return a `Foo`. Java applications typically do this using a service provider interface, and there's no reason Scala can't use the same JVM feature. – Ian McLaird Nov 04 '14 at 15:55
2

Happen to see this old post & a little curious why it can't do conditional imports in Scala? Maybe old version limit, not sure? But see this, we can import in any place of scala code.

For your scenario, it could be:

try.scala:

package my

class Foo {
}
class Bar extends Foo
object Chooser {
   val isFoo = true
}

object MyObj extends App {
  if (Chooser.isFoo) {
    import my.{Foo => MyClass}
    val a = new MyClass
    println(a)
  } else {
    import my.{Bar => MyClass}
    val a = new MyClass
    println(a)
  }
}

run output:

C:\abc\abc>scalac try.scala

C:\abc\abc>scala my.MyObj
my.Foo@6f4a47c7
atline
  • 28,355
  • 16
  • 77
  • 113
  • 1
    Under the hood, it needs both libraries to compile. However, what I was looking for was to skip the library not needed at compile time. – Jus12 Jul 07 '20 at 22:08