Scala magic to make a private/protected member visible? - scala

I am using an API where a trait is given like this:
package pkg
trait Trait {
private[pkg] def f = ...
private[pkg] val content = ...
}
I would like to access the variable content and function f in my code, using the API from a Jar file (so I cannot modify the original code to remove the private definition).
What I was able to come up with as a first solution is to create a new bridge class in the same package, that helps me access the private/protected member functions like this:
package pkg
trait PkgBridge {
def f = Trait.f
def getContent(t : Trait) = t.content;
}
This way I can call the package private members from my code.
I was wondering if there is any sophisticated way or common pattern for this kind of situations (like some magic with implicits or something?).
Thanks!

What you are doing works, is probably as good a way to do it as any, and is discouraged.
If something is package private it is probably an implementation detail for which an interface has not be specified sufficiently well to risk exposing anyone to it or to allow it to be completely private. So be careful! There may be good reason to not do this.
Aside from reflection, the only way within Scala to get at package private content is to be in that package, so your method is an appropriate one.
Note that this alternative might be useful as well:
package pkg {
trait TraitBridge extends Trait {
def fBridge = f
def contentBridge = content
}
}
and then you can
class MyClass extends TraitBridge { ... }
to specifically pick up the extensions that you want to have access to (under alternate names).

Related

Is it possible to automatically load an implicit def if included as a dependency (no importing)

I'm working on a commons library that includes a config library (https://github.com/kxbmap/configs).
This config library uses "kebab-case" when parsing configuration files by default and it can be overridden by an implicit def in scope.
However, I don't want to force that on the users of my commons library when they get access to the config library transitively.
So without me forcing users to import this implicit, like:
import CommonsConfig._
can I somehow override the naming strategy via an implicit that gets into scope by only including my commons library on the classpath. I'm guessing no but I just have to ask :)
So if not, is someone aware of another approach?
kxbmap/configs isn't that well documented to explain this.
Thanks!
Implicits work in compile time, so they cannot get magically present if something is included and then disappear if it isn't.
The closest thing would be something like:
main library
package my.library
// classes, traits, objects but no package object
extension
package my
package object library {
// implicits
}
user's code
import my.library._
however that would only work if there were no package object in main library, only one extension library could pull off this trick at once (Scala doesn't like more than one package object) and user would have to import everything available with a package, always.
In theory you could create a wrapper around all you deps, with your own configs:
final case class MyLibConfig(configsCfg: DerivationConfig)
object MyLibConfig {
implicit val default: MyLibConfig = ...
}
and then derive using this wrapper
def parseThings(args...)(implicit myLibConfig: MyLibConfig) = {
implicit val config: DerivationConfig = myLibConfig.config
// derivation
}
but in practice it would not work (parseThings would have to already know the target type or would need to have the already derived implicits passed). Unless you are up to writing your own derivation methods... avoid it.
Some way of making user just import all relevant stuff is the most maintainable strategy. E.g. you could pull off the same thing authors did and add type aliases for all types that you use, do the same for companion objects and finally put some implicits there:
package my
package object library {
type MyType = some.library.Type
val MyType = some.library.Type
implicit val derivationConfig: DerivationConfig = ...
}

Materialize implementation within package

When using a macro to materialize an implementation of a trait, I'd like to create the implementation within a package so that it has access to other package-private classes.
trait MyTrait[T]
object MyTrait {
implicit def materialize[T]: MyTrait[T] = macro materializeImpl[T]
def materializeImpl[T : c.WeakTypeTag](c: blackbox.Context): c.Expr[MyTrait[T]] = {
val tt = weakTypeTag[T]
c.Expr[MyTrait[T]](q"new MyTrait[$tt] {}")
}
}
Is it possible to materialize new MyTrait[$tt] {} within a particular package?
A macro has to expand into an AST which would compile in the place the macro call is in. Since package declarations are only allowed at top-level, and method calls aren't allowed there, the expanded tree can't create anything in another package.
As Alexey Romanov pointed out this is not possible directly. Still if you call only a few methods (and if you use macro, most probably this is so), one possible (but not perfect) workaround might be creating a public abstract class or trait that extends the target trait and "publishes" all the required package private methods as protected proxies. So you can create instances in your macro from inheriting from that abstract class rather than trait. Obviously this trick effectively "leaks" those methods to anyone but thanks to reflection anyone can call any method if he really wants. And abusing this trick will show as deliberate effort to circumvent your separation as the usage of the reflection.

Scala package private with duplicate name in package hierarchy

So I understand that in Scala, you can define something private within the scope of a specific package by adding the modifier private[packagename] where packagename is (obviously) the name of the package that you wish the reference to be private to.
So, for instance, let's say I have a package com.mycompany.usefulname with some class that has a field declared private[mycompany] - this will be accessible within all things in the com.mycompany.usefulname, as well as other things like perhaps com.mycompany.othername (or things simply in the com.mycompany, if for some reason I put something there).
What I'm wondering is this: if I do an awful design, where I have two different levels of my hierarchy using the same name, such as a package com.mycompany.mycompany, is there a way to specify which mycompany I would want something to be private within? Based on Package private modifier in Scala 2.8, it doesn't seem to be valid to specific private[com.mycompany], so how could I specify which one it would be?
Just to be clear, this is purely out of curiosity, and I'm not actually trying to make something with such an ambiguous name in the class hierarchy.
EDIT: To actually see what this does, I implemented the following hierarchy:
mycompany
mycompany
InnerObject.scala
usefulname
InnerObject2.scala
OuterObject.scala
InnerObject.scala is as follows:
object InnerObject {
private val privateVal = 7
private[mycompany] val packagePrivateVal = 8
val regularVal = 9
}
InnerObject2.scala is virtually identical:
object InnerObject2 {
private val privateVal = 7
private[mycompany] val packagePrivateVal = 8
val regularVal = 9
}
from OuterObject, I could reference:
InnerObject.regularVal
InnerObject2.packagePrivateVal
InnerObject2.regularVal
The regularVal isn't surprising, as this is public. The package private seems to be going up the hierarchy until it finds the first instance that matches the declaration of mycompany. So, can anyone tell me if/how to make it reference the outer one, rather than the inner one?
Here is the relevant excerpt (the example under the linked anchor) from the Scala language specification:
The following code illustrates the use of qualified private:
package outerpkg.innerpkg
class Outer {
class Inner {
private[Outer] def f()
private[innerpkg] def g()
private[outerpkg] def h()
}
}
Here, accesses to the method f can appear anywhere within OuterClass, but not outside it. Accesses to method g can appear anywhere within the package outerpkg.innerpkg, as would be the case for package-private methods in Java. Finally, accesses to method h can appear anywhere within package outerpkg, including packages contained in it.
There is no other mention of package-private access modifiers anywhere in the specs, at all. From this, I'd gather there is no way to deal with duplicate path nodes in the package name, and Scala will take the inner-most name that it finds, as you say.
In my opinion, that's a good thing, because duplicate names are redundant and confusing.

What is the prefered way to factor out behavior

Let's say I have a couple of classes internally sharing some behavior like
def workspace = Plugin.get.reallyGet.getWorkspace
What is the best way to factor it out? I see two possibilities which can be used equivalently in the using code.
trait WorkspaceProvider {
def workspace = Plugin.get.reallyGet.getWorkspace
}
and mix it in or
object WorkspaceProvider {
def workspace = Plugin.get.reallyGet.getWorkspace
}
and import it. What would you prefer and why?
The former is preferable. The latter is essentially static, un-mockable and hard to test.
Since you're thinking in terms of coupling (a very good thing) you should familiarize yourself with the Cake Pattern (it is much covered on 'Net, starting with the paper in which the concept was first described).
You can define both:
trait WorkspaceProvider {
def workspace = Plugin.get.reallyGet.getWorkspace
}
object WorkspaceProvider extends WorkspaceProvider
The first form is more flexible. For example, it allows to be mixed at instanciation:
trait Foo { this:WorkspaceProvider =>
def bar = workspace.doSomethingRelevantHere
}
val myFoo = new Foo with WorkspaceProvider
But the second form is more convenient if you just want to use the workspace method. For example in tests, prototypes, etc.
EDIT:
For a little more elaboration about this approach, check out "Selfless Trait Pattern", where Bill Venners shows how it is implemented in ScalaTest.

In Scala, how can I define a companion object for a class defined in Java?

I'd like to add implicit conversions to Java classes generated by a modeling tool. So I want to add them to the companion object of those classes, so that the compiler automatically finds them. But I cannot add them in a separate file, because the companion has to be defined in the same file. Is there anything I can do about this?
Of course, I can define all my implicit conversions in another object and then bring it into scope, but this requires an extra import. Any other solution?
You can define your own companion object of course, which I often do in my own project-specific Predef-like arrangement. For example:
object domain {
type TimeUnit = java.util.concurrent.TimeUnit
object TimeUnit {
def valueOf(s : String) = java.util.concurrent.TimeUnit.valueOf(str)
val Millis = java.util.concurrent.TimeUnit.MILLISECONDS
//etc
}
Then this can be used:
import my.domain._
val tu : TimeUnit = TimeUnit.valueOf("MILLISECONDS")
But your domain.TimeUnit is a module (i.e. scala object)
With the Scala compiler as it stands now there is no way to define companion objects other than by putting them in the same file. The best you can do is a non-companion object with the same package and name and an extra import.
If you can think of a good way to create post-hoc companionship without breaking assumptions about encapsulation please come post on http://groups.google.com/group/scala-debate because it would clearly be a very useful feature.