"Modular" Scala guidelines
Asked Answered
G

4

14

Recently I've become confused how to organize my Scala code, because there are a lot of options.

Are there any guidelines for Scala how/when to use packages, objects, package objects for organizing code?

Grandniece answered 26/7, 2011 at 13:13 Comment(1)
not a guideline but Netbeans has problems accessing case classes defined inside another object, though this has nothing to do with the compiler. In my case, I don't do case classes inside another class or object.Exurbanite
L
9

Understanding Scala's capabilities

First, we need to understand the capabilities and limitations of each modularization strategy.

Packages

These work just like in Java. You can use many files to declare different parts of one package, and you can nest many levels deep. This provides maximum flexibility with your layout. However, since the default classloaders expect to only find classes and interfaces in packages, that's all Scala lets you put there. (Classes, traits, and objects.)

Objects

Objects can contain anything--methods, fields, other objects, classes, traits, etc.. Subclasses, traits, and objects are actually their own separate entities with the containing object as a name-mangled prefix (as far as the JVM is concerned). An object must be contained wholly within one file, and although you can nest subclasses arbitrarily deep, it's done via mangling increasingly long names, not adding to the path for the classloader.

Package objects

The problem with only having objects and packages is that you might want a nested structure:

scala.xml
scala.xml.include
scala.xml.include.sax

so that you need to use packages (to avoid having one gigantic file and disturbingly long class names). But you also might want

import scala.xml._

to make various constants and implicit conversions available to you, so that you need to use an object. Package objects come to the rescue; they are essentially the same as ordinary objects, but when you say

import scala.xml._

you get both everything in the package (scala.xml._) but also everything in the corresponding package object (scala.xml.package).

How to modularize your code

Now that we know how each part works, there are fairly obvious rules for how to organize:

  • Place related code into a package
  • If there are many related sub-parts, place those into sub-packages
  • If a package requires implicits or constants, put those into the package object for that package
  • If you have a terminal branch of your package hierarchy, it is your choice as to whether it should be an object or a package object. There are a few things that package objects are not allowed to do (though the list is getting smaller all the time--I'm not sure there's anything left except a prohibition against shadowing other names in the package), so a regular object might be a better choice. As long as you're not worried about binary compatibility, it's easy to change your mind later--just change object to package object in most cases.
Leontineleontyne answered 27/7, 2011 at 3:19 Comment(2)
what about sbt subprojects?!Vaudevillian
@ŁukaszRzeszotarski - That's another interesting question, but this one specifically asked about Scala features, not build tools. You could talk for a very long time about how to use build tools to help organize your Scala projects.Leontineleontyne
L
2

Besides packages and objects there are 'implicits' which help you structuring your code. A nice guideline for using (avoid misuse) can be found here: http://suereth.blogspot.com/2011/02/slides-for-todays-nescala-talk.html

I would also suggest type classes to structure your code. Here a nice write up on this topic: http://debasishg.blogspot.com/2010/07/refactoring-into-scala-type-classes.html

Leaseholder answered 27/7, 2011 at 8:44 Comment(2)
I use both of them. It's one of the reasons why I ask how to organize code. However, I believe your answer is useful for those who will stumble upon this question to give them another insight.Grandniece
To give code structure quite a lot of concepts and abstractions can be used. Implicits themselves are powerful yet be easily missused. That's why I suggest also the typeclass approach. If you like my answer you may upvote it also ;)Leaseholder
B
1

I use packages whenever I can, that is to say, when the "module" is just made of class/traits/object definitions. Packages have the advantage of being directly accessible from Java without weird syntax.

In all other case, I use mostly plain objects.

Sometimes, I have one package object per project in the root of the project package. That package object stores all the necessary implicits and most important class and objects. It allows a nice single-line import for all the project.

Borax answered 26/7, 2011 at 14:52 Comment(0)
C
0

If you are only interested in namespacing and splitting code into separate files (as it sounds like the OP is) see @Rex's answer.

If you expect more from a module system, such as interchangeability or Standard ML-style functors, you can use the approach described here.

Basically, module interfaces (aka signatures in SML) become traits in Scala. Modules (aka structures) are objects in Scala. Functors can be translated to either classes, abstract classes, or even traits with some implementation with functor arguments converted to abstract fields or constructor arguments, depending on whether you want the resulting modules to have compatible types or not.

Criswell answered 24/6, 2014 at 2:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.