How to (properly) enrich the standard library? - scala

I would like to define an implicit conversion from Iterator[T] to a class that I have defined: ProactiveIterator[A].
The question isn't really how to do it but how to do it properly, i.e. where to place the method, so that it is as transparent and unobtrusive as possible. Ideally it should be as the implicit conversion from String to StringOps in scala.Predef If the conversion was from a class in the library to some other class, then it could be defined inside that class, but AFAIK that's not possible here.
So far I have considered to add an object containing these conversions, similarly to JavaConversions, but better options may be possible.

You don't really have much of a choice. All implicits must be contained within some sort of object, and imported with a wildcard import (you could import them individually, but I doubt you want that).
So you'll have some sort of implicits object:
package foo.bar
object Implicits {
implicit class ProactiveIterator[A](i: Iterator[A]) {
...
}
}
Then you must explicitly import it wherever you use it:
import foo.bar.Implicits._
In my opinion, this is a good thing. Someone reading the code might not understand where your pimped methods are coming from, so the explicit import is very helpful.
You can similarly place your implicits within a package object. You would have to import them the same way into other namespaces, but they would be available to classes within the same package.
For example, using the following, anything within foo.bar will have this implicit class available:
package foo
package object bar {
implicit class ProactiveIterator[A](i: Iterator[A]) {
...
}
}
Elsewhere you would import foo.bar._ (which may or may not be as clean, depending on what's in bar).

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 = ...
}

Why does class name of a type in a package object contain "package" in runtime class name?

I'm trying to generate the runtime class name of a class that is defined in a package object.
Example:
package com.foo
package object bar {
case class MyCaseClass()
}
import bar._
MyCaseClass().getClass.getCanonicalName
The above will generate com.foo.bar.package.MyCaseClass
If I use WeakTypeTag it will correctly generate the type as com.foo.bar.MyCaseClass.
package com.foo
trait MyTrait
case class MyImpl extends MyTrait
def getType[T](t: T)(implicit weakTypeTag WeakTypeTag[T]): String = {
weakTypeTag.tpe.fullName
}
What is the reason for the above difference in behavior? I know I must be missing something about the Scala type system...
This isn't so much about the type system as about the encoding of package objects on the JVM. The JVM doesn't have package-level methods, for example, so the Scala compiler has to create a synthetic class that has static methods, inner classes, etc. corresponding to the definitions in the package object. That class is named package, an arbitrary but self-explanatory name that has the advantage of being a keyword in both Scala and Java, so it's unlikely to result in collisions with non-synthetic code.
Java's reflection APIs know nothing about Scala, so naturally they can't hide this encoding from you. When you call getClass.getCanonicalName you're seeing the actual class name, corresponding to the class file you'd find at com/foo/bar/package\$MyCaseClass.class when you compile your code.
Scala's reflection APIs do know about Scala's encoding of package objects, and they will hide the synthetic package class from you. This arguably makes sense, since the details of the encoding aren't in the spec (if I remember correctly?) and so may vary across platforms or language versions, etc.
The discrepancy is a little confusing, but this isn't the only time you'll run into differences—the Scala reflection API hides lots of mangling, etc. that Java reflection can't.

How could a "global implicit class" be defined in Scala?

Considering that a implicit class "must be defined inside of another trait/class/object"1, how can a implicit conversion be defined globally?
The case is that I'd like to add a method to all Strings (or Lists) in my application, or at least to several packages of it.
One cannot add anything to the "global" scope, neither in Java, nor in Scala.
However, in Scala one can define package objects, which can contain methods that are used all over the package, and can be easily imported by the user.
This looks something like this: in the directory foo/bar/baz one creates a file called package.scala with the following content:
package foo.bar
package object baz {
implicit def incrediblyUsefulConversion(s: String) = ...
}
The user then can do the following in his code to activate the conversion:
import foo.bar.baz._
or maybe
import foo.bar.baz.incrediblyUsefulConversion
Of course, you can also use your own code in other packages, just like any other user.

Scala objects as scope

I'm a new to scala, here's a question:
object Models {
class A1 { // some methods }
class A2 { // some methods }
}
This code works and Models seems to be treated as some sort of a scoping unit - I can import it wherever I need to. Is this a normal practice? Can I use this as a way to scope parts of a package? There also seems to be a package object, which I guess behaves similarly. Are there any problems with this method that I should know about?
It's normal practice and can be used as needed. You can group some things that you might not normally be able to just inside a file (Consts for example).
val DefaultKey="12345" //not legal inside a file outside of a class or object
class A (key:String) {
}
Legal version:
package com.mytest
object KeyExchange {
val DefaultKey="12345" //now legal
class A (key:String) {
}
}
use:
object Test extends App { //extending App is like a main method
import com.mytest.KeyExchange._ //can use import statement here, bringing in class A and the const.
val myA = new A(DefaultKey)
}
The package object is kind of like this concept, except the things placed inside of it become available to the classes and traits defined as part of that package (com.mytest for example.) This is the place you might put const items that the classes will frequently use, or more importantly implicit functions and objects. You could just place all of those things in a separate file, and object, but then you'd have to import them explicitly each time. You don't have to use package objects. My understanding is that this should be used sparingly, for items you're certain most classes can make use of.
reference:
http://www.scala-lang.org/docu/files/packageobjects/packageobjects.html

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.