Scala code generation with annotations + macros or external script? - scala

I want to know:
Can Scala annotations/transforms implement the code generation below? (objective)
What are the trade-offs as opposed to source code generation with an external tool? (objective)
Is there a better way / how would you do it? (subjective)
Background:
I'm designing an embedded database for Scala + Java as a side project. Although I want it to be usable from Java, I'm writing it in Scala for the extra flexibility/power and because writing Java code kills my soul.
I'm working out what I want model definitions to look like. My initial idea was to parse some model definition files and generate Scala classes. But I think now I'd like them to be definable in Scala code so that no parsing is required and people can bring the full power of Scala to bear in defining and customizing the models (e.g. custom column types.) That's a valuable feature from my Python/Django experience.
So far I have something like:
#model
class Person {
val Name = StringColumn(length=32)
val BirthDate = DateColumn(optional=true)
}
#model
class Student extends Person {
val GPA = FloatColumn(propertyName="gpa")
}
#model
class Teacher extends Person {
val salary = NumericColumn()
}
Which would generate:
class Person {
val Name = StringColumn(name="name", length=32)
val BirthDate = DateColumn(name="birthDate", optional=true)
// generated accessor methods
def name = Person.Name.get(...)
def name_= (name : String) : Unit = Person.Name.set(..., name)
// etc ...
}
// static access to model metadata, e.g. Person.Name is an immutable StringColumn instance
object Person extends Person
class Student extends Person {
val GPA = DoubleColumn(name = "GPA")
def gpa = ...
def gpa_= (value : Float) = ...
}
object Student extends Student
class Teacher extends Person {
// You get the idea
}
object Teacher extends Teacher
Looking at some examples online and doing some research, it seems like AST transforms using a special #model annotation could actually generate the needed code, maybe with a little bit of help, e.g. having the user define the object as well with the model definition. Am I right that this can be done?
Some problems that occur to me with this idea:
The object will be cluttered with properties that are not useful, all it needs are the Column objects. This could be fixed by splitting the class into two classes, PersonMeta and Person extends PersonMeta with Person object extending PersonMeta only.
IDEs will probably not pick up on the generated properties, causing them to underline them with wavy lines (eww...) and making it so auto-complete for property names won't work. The code would still be compile-time checked, so it's really just an IDE gotcha (Dynamic, no doubt, has the same problem.)
Code generation using a script is more IDE friendly, but it's hacky, probably more work, especially since you have to leave custom methods and things intact. It also requires a custom build step that you have to run whenever you change a model (which means you can forget to do it.) While the IDE might not help you with macro code generation (yet, anyway) the compiler will shout at you if you get things wrong. That makes me lean towards doing it with macros + annotation.
What do you think? I'm new to Scala, I kind of doubt I've hit on the best way to define models and generate implementations for them. How would you do it better?

It's possible yeah. Macros can be unpleasant to write and debug, but they do work.
Seems like you already have your solution there
Scala IDEs tend to handle macros correctly-ish (I mean, they have to, they're part of the language and used in some pretty fundamental libraries), so I wouldn't worry about that; if anything a macro is more ide-friendly than an external codegen step because a macro will stay in sync with a user's changes.
I'd see whether you can achieve what you want in vanilla scala before resorting to a macro. Remember that your class-like things don't necessarily have to be actual case classes; take a look at Shapeless generic records for an idea of how you can represent a well-typed "row" of named values from somewhere external. I think a system that could map a structure like those records to and from SQL might end up being more principled (that is, easier to reason about) than one based on "special" case classes.

Related

why I can update state of an Object extend immutable trait in scala

I created a class extend scala.Immutable
class SomeThing(var string: String) extends Immutable {
override def toString: String = string
}
As I expected, scala compiler should help me prevent change state of class SomeThing. But when I run this test
"Test change state of immutable interface" should "not allow" in {
val someThing = new SomeThing("hello")
someThing.string = "hello 1"
println(someThing)
}
The result is hello 1 and scala compiler don't throw any warning or error.
Why they have to add Immutable trait without help us prevent object mutable?
There are several aspects to this question.
1. A simple one is that Scala compiler can't really ensure immutability for many various reasons. For example, the main target platform JVM allows modifying even final fields using reflection. Another reason this is not enforceable is code like this
/////////////////////////////////////////
//// library v1
package library
class LibraryData(val value:Int)
/////////////////////////////////////////
//// code that uses the library
package app
class UserData(val data:LibraryData) extends Immutable
/////////////////////////////////////////
//// library v2
package library
class LibraryData(var value:Int) //now change it to var!
Since the "library" is compiled independently of the "app" and doesn't even know about existence of the "app" there is no point in time where compiler can catch the broken contract.
2. More fundamental misunderstanding you seem to have is what trait does. In this context trait (or "interface" in some other languages) represents a contract between the implementation and the user-code about how the implementation can and should behave. However not every kind of a contract can be represented as a trait (at least without making the code super-complicated). For example, for a mutable collection there is a contract that size should return the number of times add (or +=) has been called but there is no way to represent such a contract as a trait besides declaring that there are methods size and += with corresponding signatures. On the other hand, for most of the contracts there is no way to enforce implementation to follow the contract . For example, an implementation of size that always returns 0 technically matches all the types but is clearly breaking the contract.
Similarly Immutable doc says:
A marker trait for all immutable data structures such as immutable collections.
So it is just a marker trait which is one of the ways to work around contracts that can't be really represented as types. And it says that whoever implements that trait claims to be an immutable object. Your code claims that but clearly breaks the contract. So technically it is your fault for not respecting the contract.

Scala type alias with companion object

I'm a relatively new Scala user and I wanted to get an opinion on the current design of my code.
I have a few classes that are all represented as fixed length Vector[Byte] (ultimately they are used in a learning algorithm that requires a byte string), say A, B and C.
I would like these classes to be referred to as A, B and C elsewhere in the package for readability sake and I don't need to add any extra class methods to Vector for these methods. Hence, I don't think the extend-my-library pattern is useful here.
However, I would like to include all the useful functional methods that come with Vector without having to 'drill' into a wrapper object each time. As efficiency is important here, I also didn't want the added weight of a wrapper.
Therefore I decided to define type aliases in the package object:
package object abc {
type A: Vector[Byte]
type B: Vector[Byte]
type C: Vector[Byte]
}
However, each has it's own fixed length and I would like to include factory methods for their creation. It seems like this is what companion objects are for. This is how my final design looks:
package object abc {
type A: Vector[Byte]
object A {
val LENGTH: Int = ...
def apply(...): A = {
Vector.tabulate...
}
}
...
}
Everything compiles and it allows me to do stuff like this:
val a: A = A(...)
a map {...} mkString(...)
I can't find anything specifically warning against writing companion objects for type aliases, but it seems it goes against how type aliases should be used. It also means that all three of these classes are defined in the same file, when ideally they should be separated.
Are there any hidden problems with this approach?
Is there a better design for this problem?
Thanks.
I guess it is totally ok, because you are not really implementing a companion object.
If you were, you would have access to private fields of immutable.Vector from inside object A (like e.g. private var dirty), which you do not have.
Thus, although it somewhat feels like A is a companion object, it really isn't.
If it were possible to create a companion object for any type by using type alias would make member visibility constraints moot (except maybe for private|protected[this]).
Furthermore, naming the object like the type alias clarifies context and purpose of the object, which is a plus in my book.
Having them all in one file is something that is pretty common in scala as I know it (e.g. when using the type class pattern).
Thus:
No pitfalls, I know of.
And, imho, no need for a different approach.

Self-titled field and accessor in Scala

It was empirically discovered that Scala allows name clashes for object-private variables and methods like below:
class Test {
private[this] var x = 1
def x(): String = this.x.toString
}
This code is valid at least for Scala 2.10 and produces exactly what I expect (decompiled into Java):
public class Test {
private int x;
public String x() {
return BoxesRunTime.boxToInteger(x).toString();
}
public Test() {
x = 1;
}
}
The problem is that I'm not sure if I can rely on this behavior in later Scala releases because I was not able to find an authoritative proof in the specifications that this behavior is by design. So, can anybody suggest me such a source of knowledge?
Update: My goal is to use this approach to map Hibernate data model with Scala classes. Since there is no easy way to enable Hibernate to support Scala collections, I wanted to map a Java collection in a private field which is then wrapped into a Scala collection in a self-titled accessor method. The key requirement is to keep the field and the method with the same name because I want also to preserve the logical Hibernate collection name, e.g. to reference it in HQL.
these collisions are totally normal. But keep in mind that reading your code might become a problem, since these collisions should appear (if you need that) only for getters/setters.
In other case please use clear method names like:
def xAsString():
This thread can also be helpful scala discussion on name collisions
and this naming conventions by Daniel Spewaks

Explanation of singleton objects in Scala

I get the coding in that you basically provide an "object SomeClass" and a "class SomeClass" and the companion class is the class declaration and the object is a singleton. Of which you cannot create an instance. So... my question is mostly the purpose of a singleton object in this particular instance.
Is this basically just a way to provide class methods in Scala? Like + based methods in Objective-C?
I'm reading the Programming in Scala book and Chapter 4 just talked about singleton objects, but it doesn't get into a lot of detail on why this matters.
I realize I may be getting ahead of myself here and that it might be explained in greater detail later. If so, let me know. This book is reasonably good so far, but it has a lot of "in Java, you do this", but I have so little Java experience that I sort of miss a bit of the points I fear. I don't want this to be one of those situations.
I don't recall reading anywhere on the Programming in Scala website that Java was a prerequisite for reading this book...
Yes, companion singletons provide an equivalent to Java's (and C++'s, c#'s, etc.) static methods.
(indeed, companion object methods are exposed via "static forwarders" for the sake of Java interop)
However, singletons go a fair way beyond this.
A singleton can inherit methods from other classes/traits, which can't be done with statics.
A singleton can be passed as a parameter (perhaps via an inherited interface)
A singleton can exist within the scope of a surrounding class or method, just as Java can have inner classes
It's also worth noting that a singleton doesn't have to be a companion, it's perfectly valid to define a singleton without also defining a companion class.
Which helps make Scala a far more object-oriented language that Java (static methods don't belong to an object). Ironic, given that it's largely discussed in terms of its functional credentials.
In many cases we need a singleton to stand for unique object in our software system.
Think about the the solar system. We may have following classes
class Planet
object Earth extends Planet
object Sun extends Planet
object is a simple way to create singleton, of course it is usually used to create class level method, as static method in java
Additional to the given answers (and going in the same general direction as jilen), objects play an important role in Scala's implicit mechanism, e.g. allowing type-class-like behavior (as known from Haskell):
trait Monoid[T] {
def zero:T
def sum(t1:T, t2:T):T
}
def fold[T](ts:T*)(implicit m:Monoid[T]) = ts.foldLeft(m.zero)(m.sum(_,_))
Now we have a fold-Function. which "collapses" a number of Ts together, as long as there is an appropriate Monoid (things that have a neutral element, and can be "added" somehow together) for T. In order to use this, we need only one instance of a Monoid for some type T, the perfect job for an object:
implicit object StringMonoid extends Monoid[String] {
def zero = ""
def sum(s1:String, s2:String) = s1 + s2
}
Now this works:
println(fold("a","bc","def")) //--> abcdef
So objects are very useful in their own right.
But wait, there is more! Companion objects can also serve as a kind of "default configuration" when extending their companion class:
trait Config {
def databaseName:String
def userName:String
def password:String
}
object Config extends Config {
def databaseName = "testDB"
def userName = "scott"
def password = "tiger"
}
So on the one hand you have the trait Config, which can be implemented by the user however she wants, but on the other hand there is a ready made object Config when you want to go with the default settings.
Yes, it is basically a way of providing class methods when used as a companion object.

Why people define class, trait, object inside another object in Scala?

Ok, I'll explain why I ask this question. I begin to read Lift 2.2 source code these days.
It's good if you happened to read lift source code before.
In Lift, I found that, define inner class and inner trait are very heavily used.
object Menu has 2 inner traits and 4 inner classes. object Loc has 18 inner classes, 5 inner traits, 7 inner objects.
There're tons of codes write like this. I wanna to know why the author write like this.
Is it because it's the author's
personal taste or a powerful use of
language feature?
Is there any trade-off for this kind
of usage?
Before 2.8, you had to choose between packages and objects. The problem with packages is that they cannot contain methods or vals on their own. So you have to put all those inside another object, which can get awkward. Observe:
object Encrypt {
private val magicConstant = 0x12345678
def encryptInt(i: Int) = i ^ magicConstant
class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] {
def hasNext = ii.hasNext
def next = encryptInt(ii.next)
}
}
Now you can import Encrypt._ and gain access to the method encryptInt as well as the class EncryptIterator. Handy!
In contrast,
package encrypt {
object Encrypt {
private[encrypt] val magicConstant = 0x12345678
def encryptInt(i: Int) = i ^ magicConstant
}
class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] {
def hasNext = ii.hasNext
def next = Encrypt.encryptInt(ii.next)
}
}
It's not a huge difference, but it makes the user import both encrypt._ and encrypt.Encrypt._ or have to keep writing Encrypt.encryptInt over and over. Why not just use an object instead, as in the first pattern? (There's really no performance penalty, since nested classes aren't actually Java inner classes under the hood; they're just regular classes as far as the JVM knows, but with fancy names that tell you that they're nested.)
In 2.8, you can have your cake and eat it too: call the thing a package object, and the compiler will rewrite the code for you so it actually looks like the second example under the hood (except the object Encrypt is actually called package internally), but behaves like the first example in terms of namespace--the vals and defs are right there without needing an extra import.
Thus, projects that were started pre-2.8 often use objects to enclose lots of stuff as if they were a package. Post-2.8, one of the main motivations has been removed. (But just to be clear, using an object still doesn't hurt; it's more that it's conceptually misleading than that it has a negative impact on performance or whatnot.)
(P.S. Please, please don't try to actually encrypt anything that way except as an example or a joke!)
Putting classes, traits and objects in an object is sometimes required when you want to use abstract type variables, see e.g. http://programming-scala.labs.oreilly.com/ch12.html#_parameterized_types_vs_abstract_types
It can be both. Among other things, an instance of an inner class/trait has access to the variables of its parent. Inner classes have to be created with a parent instance, which is an instance of the outer type.
In other cases, it's probably just a way of grouping closely related things, as in your object example. Note that the trait LocParam is sealed, which means that all subclasses have to be in the same compile unit/file.
sblundy has a decent answer. One thing to add is that only with Scala 2.8 do you have package objects which let you group similar things in a package namespace without making a completely separate object. For that reason I will be updating my Lift Modules proposal to use a package object instead of a simple object.