I am learning Scala now and I want to write some silly little app like a console Twitter client, or whatever. The question is, how to structure application on disk and logically. I know python, and there I would just create some files with classes and then import them in the main module like import util.ssh or from tweets import Retweet (strongly hoping you wouldn’t mind that names, they are just for reference). But how should I do this stuff using Scala? Also, I have not much experience with JVM and Java, so I am a complete newbie here.
I am learning Scala now and I want to write some silly little app
Share
I’m going to disagree with Jens, here, though not all that much.
Project Layout
My own suggestion is that you model your efforts on Maven’s standard directory layout.
Previous versions of SBT (before SBT 0.9.x) would create it automatically for you:
So you’ll put your source files inside
myproject/src/main/scala, for the main program, ormyproject/src/test/scala, for the tests.Since that doesn’t work anymore, there are some alternatives:
giter8 and sbt.g8
Install giter8, clone ymasory’s sbt.g8 template and adapt it to your necessities, and use that. See below, for example, this use of unmodified ymasory’s sbt.g8 template. I think this is one of the best alternatives to starting new projects when you have a good notion of what you want in all your projects.
np plugin
Use softprops’s np plugin for sbt. In the example below, the plugin is configured on
~/.sbt/plugins/build.sbt, and its settings on~/.sbt/np.sbt, with standard sbt script. If you use paulp’s sbt-extras, you’d need to install these things under the right Scala version subdirectory in~/.sbt, as it uses separate configurations for each Scala version. In practice, this is the one I use most often.mkdir
You could simply create it with
mkdir:Source Layout
Now, about the source layout. Jens recommends following Java style. Well, the Java directory layout is a requirement — in Java. Scala does not have the same requirement, so you have the option of following it or not.
If you do follow it, assuming the base package is
org.dcsobral.myproject, then source code for that package would be put insidemyproject/src/main/scala/org/dcsobral/myproject/, and so on for sub-packages.Two common ways of diverging from that standard are:
Omitting the base package directory, and only creating subdirectories for the sub-packages.
For instance, let’s say I have the packages
org.dcsobral.myproject.model,org.dcsobral.myproject.viewandorg.dcsobral.myproject.controller, then the directories would bemyproject/src/main/scala/model,myproject/src/main/scala/viewandmyproject/src/main/scala/controller.Putting everything together. In this case, all source files would be inside
myproject/src/main/scala. This is good enough for small projects. In fact, if you have no sub-projects, it is the same as above.And this deals with directory layout.
File Names
Next, let’s talk about files. In Java, the practice is separating each class in its own file, whose name will follow the name of the class. This is good enough in Scala too, but you have to pay attention to some exceptions.
First, Scala has
object, which Java does not have. Aclassandobjectof the same name are considered companions, which has some practical implications, but only if they are in the same file. So, place companion classes and objects in the same file.Second, Scala has a concept known as
sealed class(ortrait), which limits subclasses (or implementingobjects) to those declared in the same file. This is mostly done to create algebraic data types with pattern matching with exhaustiveness check. For example:If
Treewas notsealed, then anyone could extend it, making it impossible for the compiler to know whether the match was exhaustive or not. Anyway,sealedclasses go together in the same file.Another naming convention is to name the files containing a
package object(for that package)package.scala.Importing Stuff
The most basic rule is that stuff in the same package see each other. So, put everything in the same package, and you don’t need to concern yourself with what sees what.
But Scala also have relative references and imports. This requires a bit of an explanation. Say I have the following declarations at the top of my file:
Everything following will be put in the package
org.dcsobral.myproject.model. Also, not only everything inside that package will be visible, but everything insideorg.dcsobral.myprojectwill be visible as well. If I just declaredpackage org.dcsobral.myproject.modelinstead, thenorg.dcsobral.myprojectwould not be visible.The rule is pretty simple, but it can confuse people a bit at first. The reason for this rule is relative imports. Consider now the following statement in that file:
This import may be relative — all imports can be relative unless you prefix it with
_root_.. It can refer to the following packages:org.dcsobral.myproject.model.view,org.dcsobral.myproject.view,scala.viewandjava.lang.view. It could also refer to an object namedviewinsidescala.Predef. Or it could be an absolute import refering to a package namedview.If more than one such package exists, it will pick one according to some precedence rules. If you needed to import something else, you can turn the import into an absolute one.
This import makes everything inside the
viewpackage (wherever it is) visible in its scope. If it happens inside aclass, andobjector adef, then the visibility will be restricted to that. It imports everything because of the._, which is a wildcard.An alternative might look like this:
In that case, the packages
viewandcontrollerwould be visible, but you’d have to name them explicitly when using them:Or you could use further relative imports:
The
importstatement also enable you to rename stuff, or import everything but something. Refer to relevant documentation about it for more details.So, I hope this answer all your questions.