Val defined in package object unaccessable in other classes - scala

I have the following package object with a val declared in it
package au.com.someproject.protocol
package object helpers {
val etcdRoot = "someproject.com.au"
}
This package object is declared as part of an API, when I import the API into another project and I try to access the variable I meet with the following error
[error] /home/user/git/company/project/project-agent/src/main/scala/au/com/someproject/project_agent/cluster/StatusMonitor.scala:52: not found: value etcdRoot
[error] etcdClient.setKey(s"$etcdRoot/kumo/peers/${systemCluster.selfAddress.host.get}", systemCluster.selfAddress.port.get.toString, new Some(40.seconds))
I'm importing the variable like so, how I would except it should be done
import au.com.someproject.protocol.helpers._
But yet I get the error, is there something I am doing wrong with the declaration or importing?

There's usually a catch with package objects, they have to be manually placed inside the package folder, meaning I would expect your directory structure to look like this before the import would work.
src/main/scala/au/com/someproject/protocol/helpers/helpers.scala
And inside the helpers/, you define your package object. Sometimes you are tempted to have it like the below:
src/main/scala/au/com/someproject/protocol/helpers.scala
The above doesn't actually define the package object on the helpers package, you need to follow the specific directory structure and manually define the package before you define the package object inside it.

Related

How to make definitions inside root package objects accessible to inner packages directly?

Assume that an application has following package structure:
root_package
- inner_package1
- inner_0
- inner_1
- inner_package2
So, root_package is the parent package. Similarly, packages inner_package1, inner_package2 are packages defined inside the parent package and so on..
Now, we know that Scala allows us to put together common definitions, variables, methods etc needed by the codebase within the package using a package object.
Here, I define define a package object for root_package as follow:
package object root_package {
type Dictionary = Map[String, Any]
}
Now, the type Dictionary becomes directly usage to the codebase placed at 1-level under root_package, but can't be directly accessible from inner packages and deeper nested levels.(It can only be done using import which somewhat defeats the purpose for me).
Is there some way where I can define package objects such that the common definitions are directly accessible to all the sub-packages or inner-packages without additional import statements ?

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

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.

Types defined in a package object aren't in scope

To avoid writing out a large type in several places in my code, I thought I'd shortcut it using a type declaration in a package object:
package pet
package object pet {
type Ops = ((Int,Int) => Int,String)
}
object Q extends App {
val ops = List[Ops](
((_+_),"+"),
((_-_),"-"),
((_*_),"*")
)
}
But it's saying that for val ops, Ops isn't found. I'm guessing I'm misunderstanding something, but after looking over several package object examples, I can't tell what. There are no errors in the package object itself, so I don't think that it's a problem with that.
When declaring a package object, you need to place it in the package "above". As it stands, you're declaring package object pet inside package pet, so that Ops is actually located at the path pet.pet.Ops.
In your case, you should just place the package object inside it's own file without any package declaration.
If you were to import pet.pet._ inside Q it would also work.
Each package is allowed to have one package object. Any definitions
placed in a package object are considered members of the package
itself.
As seen from here, the definitions are package specific (in this case pet.pet). So you need to import them for use.
You can try:
object Q extends App {
import pet.pet._
...

How to define a global function in scala?

I'm using play framework, I want to define a global function, How can I do it?
First I define the function in SomeFunc.scala and import it to every file which I will use it.
Is it possible to direct use it like println without import SomeFunc.scala
println is defined in the object scala.Predef. The members of which is always in scope, there is no way you can add to that, but as the question linked to by senia says you can achieve sort of the same by defining a method in a package object which will then be available inside code in that package.
Another solution that some libraries uses is to provide an Imports object with aliases and shortcuts just like Predef, but that you have to explicitly import with a wildcard. For example nscala-time does this:
import com.github.nscala_time.time.Implicits._
Yes it is possible, but only global in the same package, not absolute global.
package com
package object myproject {
def myGlobalFunc(..) = ...
}
Then you use it like this:
package com.myproject
object HelloWorld {
def main(args: Array[String]) {
myGlobalFunc(...)
}
}