I have found kind of a weirdness in the following Scala program (sorry to include all the code, but you'll see why I added it all) :
object md2html extends App {
private val DEFAULT_THEME = Themes.AMAZON_LIGHT
private val VALID_OPTIONS = Set("editorTheme", "logo", "style")
try {
// some code 1
} catch {
case t: Throwable => t.printStackTrace(); exitWithError(t.getMessage)
}
// some code 2 (method definitions only)
private def parseOption(key: String, value: String) = {
println(key + " " + VALID_OPTIONS)
if (! Set("theme","editorTheme", "logo", "style").contains(key)) exitWithError(s"$key is not a valid option")
if (key == "theme") Themes(value).toMap else Map(key.drop(2) -> value)
}
// some code 3 (method definitions only)
}
If VALID_OPTIONS is defined after one of the some code..., it is evaluated to null in parseOption. I can see no good reason for that. I truncated the code for clarity, but if some more code is required I'll be happy to add it.
EDIT : I looked a bit more into it, and here is what I found.
When extending App, the val is not initialized with this code
object Test extends App {
printTest()
def printTest = println(test)
val test = "test"
}
With a regular main method, it works fine :
object Test {
def main(args: Array[String]): Unit = {
printTest
}
def printTest = println(test)
val test = "test"
}
I had overseen that you use extends App. This is another pitfall in Scala, unfortunately:
object Foo extends App {
val bar = "bar"
}
Foo.bar // null!
Foo.main(Array())
Foo.bar // now initialized
The App trait defers the object's initialization to the invocation of the main method, so all the vals are null until the main method has been called.
In summary, the App trait and vals do not mix well. I have fallen into that trap many times. If you use App, avoid vals, if you have to use global state, use lazy vals instead.
Constructor bodies, and this goes for singleton objects as well, are evaluated strictly top to bottom. This is a common pitfall in Scala, unfortunately, as it becomes relevant where the vals are defined if they are referenced in other places of the constructor.
object Foo {
val rab = useBar // oops, involuntarily referring to uninitialized val
val bar = "bar"
def useBar: String = bar.reverse
}
Foo // NPE
Of course, in a better world, the Scala compiler would either disallow the above code, re-order the initialization, or at least warn you. But it doesn't...
Related
I have Scala class which methods use a lot of regex. Each class method use some regex patterns.
Looking from the perspective of code modularity I should store those patterns in method:
class Bar {
def foo() {
val patt1 = "[ab]+".r
val patt2 = "[cd]+".r
/*...*/
}
}
But this approach is quite inefficient. Patterns are recompiled on each method call.
I could move them directly to class:
class Bar {
val fooPatt1 = "[ab]+".r
val fooPatt2 = "[cd]+".r
/*...*/
}
but in case when I have 30 methods it looks ugly.
I ended up with some hybrid solution using val and anonymous function:
val z = {
val patt1 = "[ab]+".r
val patt2 = "[cd]+".r
() => { /* ... */ }
}
but I am not sure if using val to store function have some drawbacks compared to def. Maybe there is other clean solution to store methods constants without polluting the class?
Using a val is perfectly fine. There might be a (very) small performance hit, but in most (99.9%) of the applications that's not a problem.
You could also create a class for the method
// The extends is not needed, although you might want to hide the Foo type
class Foo extends (() => ...) {
val patt1 = "[ab]+".r
val patt2 = "[cd]+".r
def apply() = {
...
}
}
Then in the class:
class Bar {
val foo = new Foo
}
Another solution is using traits
trait Foo {
private lazy val patt1 = "[ab]+".r
private lazy val patt2 = "[cd]+".r
def foo() = ...
}
class Bar extends Foo with ...
Note that if you have different methods like that in a single class, it can be sign that the single responsibility principle is violated. Moving them to their own class (or trait) can be a solution for that problem as well.
I would put every method with the necessary regex in it's own Trait:
class Bar extends AMethod with BMethod
trait AMethod {
private val aPattern = """\d+""".r
def aMethod(s: String) = aPattern.findFirstIn(s)
}
trait BMethod {
private val bPattern = """\w+""".r
def bMethod(s: String) = bPattern.findFirstIn(s)
}
clean
separated
easy to test (object AMethodSpec extends Properties("AMethod") with AMethod ...)
I took into account Chris comment. Putting patterns to companion object is probably the most efficient approach but very unclean when we have more methods.
EECOLOR solution is less efficient but cleaner. Traits prevents recreating patterns on each method call. Unfortunately, scala do not use same compiled pattern accross multiple class instances:
(new X).patt1==(new X).patt1 // would be false.
I've combined those two approaches and instead traits I used objects.
object X {
object method1 {
val patt1 = "a".r
}
object method2 {
val patt1 = "a".r
}
}
class X {
def method1 = {
import X.method1._
patt1
}
def method2 = {
import X.method2._
patt1
}
}
(new X).method1 == (new X).method1 // true
(new X).method2 == (new X).method2 // true
Although this approach works, I think scala should provide some solution for that problem out of box. Patterns are the simplest example. We could have other immutable objects which initialization is much more expensive.
Extracting method internals somewhere outside is still unclear. It would be nice to do it like with lazy vals. Adding one modificator should ensure that value is instance only once across all instances and methods calls. It would be something like that:
def method1 {
static val x = new VeryExpensiveObject
}
How do I get this to work, I've tried with and without new keyword:
object Main extends App {
override def main (args : Array[String] = new Array("default argument")) {
println("args(0) = " + args(0))
}
}
http://ideone.com/5AyTxy (I have tried other [1, 2] methods but I think that its val is causing issues)
Docs: http://docs.scala-lang.org/sips/completed/named-and-default-arguments.html#default_arguments
PS: I should confirm that I want this to be bound to the args name; rather than to another var or val. Additionally the scope needs to be global within main.
Two notes:
1) When you extend App, the body of your object is your main function. "args" is a supplied value, you can just use it.
object MyApp extends App {
println(args)
}
2) main will always be called with arguments. This makes sense, since otherwise Scala (and Java) would be inconsistent. The JVM doesn't test to see if you have any arguments before passing the arg list to your main function. If it did, it would call main(Array("args")) sometimes, and main() other times, which would create a problem!
A better way to do this would be to actually use args as it is:
object MyApp extends App {
println(args.toList.headOption.getOrElse("Default first argument"))
}
If you want more than one argument though, you should check out a real argument parsing library, I recommend scopt.
To satisfy your intent here (as clarified by your last comment to #AlexIv's answer) - keeping the field name of args while allowing for a default value for the field - you can override the field, using a reference to the original value prefixed by super.:
object Main extends App {
override val args: Array[String] = if (super.args.isEmpty) Array("default argument") else super.args
println("args(0) = " + args(0))
}
You have to remove extends App and new:
object Main {
def main (args : Array[String] = Array("default argument")) {
println("args(0) = " + args(0))
}
}
But this won't help you cause main is an entry point to your application and default Array will be overwritten by the system, for example:
object Main {
def main (args : Array[String] = Array("default argument")) {
println(args.isEmpty)
}
}
Mac-mini:Desktop alex$ scalac main.scala
Mac-mini:Desktop alex$ scala Main
true
Mac-mini:Desktop alex$ scala Main hello
false
But if you need default Array, why not to make a new variable inside main?
object Main {
def main (args : Array[String] = Array("default argument")) {
val args = Array("default argument")
println(args.isEmpty)
}
}
or even shorter:
object Main extends App {
val args = Array("default argument")
println(args.isEmpty)
}
I'm trying to learn Scala and thought I would begin by reading "Scala for the Impatient". There he cites the problem of construction order by using the following classes:
class Animal {
val range: Int = 10
val env: Array[Int] = new Array[Int](range)
}
class Ant extends Animal {
override val range: Int = 2
}
and then he explained why the env ends up being an empty Array[Int] and proceeds to explain ways to prevent that, including the early definition syntax.
But... can't I prevent that just by doing this:
class Animal(val range: Int = 10) {
val env: Array[Int] = new Array[Int](range)
/* do animal stuff */
}
class Ant(override val range: Int = 2) extends Animal(range) {
/* do ant stuff */
}
??? Why is the early definition syntax really necessary?
I think a better way to look at the need for early instantiation comes from mixing in traits. With traits, you won't have a constructor that you can tweak to get around this kind of issue. Consider this very trivial and completely unrealistic example:
trait Foo{
val bar:String
val barLength = bar.length()
}
object MyFoo extends Foo{
val bar = "test"
}
As it stands right now, this code will throw a NullPointerException when MyFoo is created because bar will not yet be defined when bar.length() is invoked. But if you used early initialization, and redefined MyFoo as:
object MyFoo extends {val bar = "test"} with Foo{
}
then everything works just fine.
i need help with this code.
object test {
var list : Vector[MyType] = null
}
object foo extends MyType { // Mytype is a trait
println("TEST ")
test.list.:+(foo)
def myfunc() { //need to define this as this is there in the trait
// i do some operations
}
}
object Bar extends MyType { // Mytype is a trait
println("TEST ")
test.list.:+(Bar)
def myfunc(){
// i do some operations
}
}
now i want to go through the list and call myfunc() for all the objects that are extending MyType.
test.list foreach( t2 => t2.myfunc() )
the value's are not getting added to the list. Can someone let me know what i am doing wrong. Its not working. Is there a way to get that print statement working?
Your problem is, that the object is not constructed as a class, so that the code is called automatically. You could do two things. Either you extend App and call main or you write a function.
trait X
object test {
var list = Vector.empty[X]
}
object Foo extends App with X {
test.list :+= Foo
override def toString() = "Foo"
}
object Bar extends X {
def add() {
test.list :+= Bar
}
override def toString() = "Bar"
}
Foo.main(null)
Bar.add()
test.list foreach println
This code prints:
Foo
Bar
Extending App only adds a main methode to an object, containing all the code in the object.
You need to initialize test with an empty Vector rather than null. The way to do that in Scala is to use the factory method from the Vector object, and let type-inference do its job. For example:
var list = Vector.empty[MyType]
As you get the practice of doing that, you'll find yourself more focused on creating the data than on declaring its type, which in this case would have resolve this error before it happened.
Next the operation
test.list.:+(foo)
will not update test.list because, since Vector is immmutable, this method just returns a new updated copy and cannot affect the reference of list.
Try instead
test.list = test.list.:+(foo)
// or (with more idiomatic operator notation)
test.list = test.list :+ foo
// or (using syntactic sugar)
test.list :+= foo
I have two Scala classes that look like this (paraphrased):
abstract class GenericParser[T] {
val lineFilter : String => Boolean
parseData()
def parseData() : T {
for( line <- .... if lineFilter(line) )
// do things
}
}
class SalesParser extends GenericParser[SalesRow] {
val lineFilter = line => !line.startsWith("//")
// ....
}
The problem is that lineFilter is null in parseData, presumably because parseData is called while the primary GenericParser constructor is still running, so the subclass hasn't fully initialized its members.
I can work around this by making lineFilter a def instead of a val, but is this expected behavior? It doesn't seem right that this problem should only become apparent after getting an NPE at runtime.
It is indeed the expected behavior, and is exactly the same problem as in this question:
Scala 2.8: how to initialize child class
You can basically copy-paste the answer form that question. Solutions include:
def or lazy val instead of val
early initialization of lineFilter
redesign of your classes to avoid the “virtual method call from superclass's constructor which accesses uninitialized subclass values” problem. For instance, why would you want to store the filter function in a val or return in from a def, while it could be implemented as a method?
abstract class GenericParser[T] {
def lineFilter(line: String): Boolean
parseData()
def parseData() : T {
for( line <- .... if lineFilter(line) )
// do things
}
}
class SalesParser extends GenericParser[SalesRow] {
def lineFilter(line: String) = !line.startsWith("//")
}