Scala: How to always make certain utils available to sub packages? - scala

All my code is under package com.company.project. In almost all of my files, I end up importing some common things like import scala.util.{Failure, Try, Success} and import scala.util.control.NonFatal etc. Is it possible to somehow setup a package object in such a way that all these utils are always available to all sub packages in com.company.project.sub (kind of my own project level Predef)?

Simply create a package object with type aliases:
package com.company.project
import scala.util
package object sub {
type Failure = util.Failure
type Try = util.Try
type Success = util.Success
type NonFatal = util.control.NonFatal
}

Related

Undeclared type: createM3FromEclipseProject (Rascal)

In the following module, I tried to add myModel for debugging purpose to see the AST.
module FlowGraphsAndClassDiagrams
import analysis::flow::ObjectFlow;
import lang::java::flow::JavaToObjectFlow;
// Added to check the M3 model
import lang::java::jdt::m3::AST;
import List;
import Relation;
import lang::java::m3::Core;
import IO;
import vis::Figure;
import vis::Render;
import analysis::m3::TypeSymbol;
alias OFG = rel[loc from, loc to];
//To view the M3 model from the whole eclipse project
alias myModel = createM3FromEclipseProject(loc project);
....
When I import the above module in the rascal console, I get the following error:
Reloading module FlowGraphsAndClassDiagrams
|console:///|:Could not load FlowGraphsAndClassDiagrams
|console:///|:could not reimport FlowGraphsAndClassDiagrams
|project://my_project/src/FlowGraphsAndClassDiagrams.rsc|(428,26,<18,16>,<18,42>): Undeclared type: createM3FromEclipseProject
Advice: |http://tutor.rascal-mpl.org/Errors/Static/UndeclaredType/UndeclaredType.html|
I don't understand what the mistake is.
I think the problem lies with
alias myModel = createM3FromEclipseProject(loc project);
What are you trying to achieve with this alias? I think you don't want to use an alias, instead you want to do this:
m = createM3FromEclipseProject(|project://eLib|);
println(m);
http://tutor.rascal-mpl.org/Rascal/Rascal.html#/Rascal/Declarations/Alias/Alias.html
You can use alias to create a new name for types, while createM3FromEclipseProject(loc project) seems to be a declaration of a function. If you want to call a function, which you seem to be doing, you need to provide a variable/value as parameter: createM3FromEclipseProject(|project://eLib|) if you want to "create an M3" from eclipse project "eLib".
Both answers are right, you can't use aliases for global variables. If you want to make an global variable (which in most cases we advice against), you have to give the type of that variable. We only allow type inference for local variables.
So in your specific case it should be:
M3 myModel = createM3FromEclipseProject(|project://eLib|);
In most cases you want to do this in your main method instead of at module import time.

Unable to import ChannelSftp.LsEntry from Jsch when I use it in Scala code, why?

So in my scala class, I had to use the Jsch(JAVA) library to do SFTP work. But for some reason, it is unable to import:
import com.jcraft.jsch.ChannelSftp.LsEntry
Any idea why this would be? LsEntry is a nested class of ChannelSftp.
http://epaul.github.io/jsch-documentation/simple.javadoc/com/jcraft/jsch/ChannelSftp.html
package services.impl
import java.nio.file.Path
import com.jcraft.jsch.ChannelSftp
import com.jcraft.jsch.ChannelSftp.LsEntry
import services.InputService
class InputServiceImpl extends InputService[List[ChannelSftp.LsEntry]] {
}
Figured it out.
In scala, to reference an nested class, you use the following syntax:
ChannelSftp#LsEntry

Usage of the `import` statement

Can someone explain me how the import statement works ?
For example I have a type User in the myapp/app/models package:
package models
type User struct {
// exportod fields
}
I have a type Users in the myapp/app/controllers package:
package controllers
import (
_ "myapp/app/models"
"github.com/revel/revel"
)
type Users struct {
*revel.Controller
}
func (c Users) HandleSubmit(user *User) revel.Result {
// Code here
}
This gives me the following error:
undefined: User
I tried to change the imports to the following code:
import (
. "advorts/app/models"
"github.com/revel/revel"
)
But get this error:
undefined: "myapp/app/controllers".User
Which I don't understand either. So, what is the difference between import . "something" and import "something" ? How to properly import my model in my case ?
Each package has a set of types, functions, variables, etc. Let's call them entities. Each entity can be either exported (its name start with an Uppercase letter), or unexported (its name start with a lowercase letter).
A package can only access the exported entites of another package. To do this, it needs to import it, which will make the exported entites available with the package name as identifier. Example:
import "github.com/revel/revel"
will get all exported entites of the revel package, which will be available using revel. prefix. As in revel.Controller, which is the Controller type defined in the revel package.
You can alias a package identifier by prefixing the import path with the wanted identifier. Example:
import rev "github.com/revel/revel"
will import all revel entites with the identifier rev. So revel.Controller becomes rev.Controller. It is useful if you have multiple package with the same name, or a package with an absurdly long name.
As a bonus, you can import a package anonymously, by aliasing it to the blank identifier:
import _ "github.com/revel/revel"
which will import the package, but not give you access to the exported entities. It is useful for things like drivers, which you need to import but never access. A frequent example is the database drivers, which register themselves to the database/sql package so you never need to access them directly.
And as a bonus' bonus, you can also import locally a package, by aliasing it with the . identifier. The exported entites will then be available without identifier, as if you defined them in the same package.
How to properly import your packages is up to you. The general convention is to never alias if you can manage it, to hide the package that you don't need to access but still need to import (database drivers), and that's all. You really never need to import locally a package, even if some tutorials or frameworks do it for simplicity's sake.

scala: can't import object from root scope

I Have the following code:
(src/main/scala/coins/coins.scala)
object Main extends App {
def countChange(money: Int, coins: List[Int]): Int = {
[...]
And I'm trying to reference it from a test like this:
(src/test/scala/coins/CoinsSuite.scala)
package coins
import org.scalatest.FunSuite
class CoinsSuite extends FunSuite {
import Main.countChange
test("only onw way to pay $0") {
[...]
And I get the following error:
not found: value Main
[error] import Main.countChange
But on the other hand, from an sbt console it works fine
If I declare any package in the main file, like
package x
object Main extends App {
Console.println("Hello World!")
Then I can correcly issue
import x.Main.countChange
Is there limitation on root package or on singleton objects visibility that I'm not aware of?
-- added
just to complete the answer, a couple of useful links at SO
https://stackoverflow.com/a/2030159/47633
https://stackoverflow.com/a/9822212/47633
https://stackoverflow.com/a/9822227/47633
Java (and Scala according to the same convention) is grumpy about importing things in the unnamed package, which is not the same thing as the root package. Put Main into a package.
See Why is my object not a member of package <root> if it's in a separate source file?

Why does my Scala enumeration break when I move it to another package?

Enumeration code looks like the following
package com.mydomain
object Market extends Enumeration {
type Market = Value
val ASX, LSE = Value
}
I try to use as follows
import com.mydomain.Market._
.
.
.
if (Market.ASX == currentMarket) {
...
}
This was working when everything was in the same package. When I moved to a new package I now get
not found: value Market
If you import Market, you have ASX and LSE directly available to you. You don't have Market.ASX available--that would be if you had object Market available, which is what would happen if you did import com.mydomain._.
Being inside package com.mydomain causes com.mydomain._ to be loaded just like you imported it, so that's why you can say Market.ASX when you're in the same package.
When you write code in a different package, you need to either import com.mydomain._ and then use Market.ASX, or import com.mydomain.Market._ and then use ASX.