I am trying to add a setter method in an object:
object Foo {
def foo_=(s: String) = println(s)
}
Foo.foo = "test"
This does not work as expected, and compiler complains about "value foo is not a member of object Foo".
Why does it not work? How can I make it work, other than make a setter method without _=?
This seems to work just right in Scala 2.13
object Foo {
private var f: String = ""
def foo_=(s: String): Unit =
this.f = s.toLowerCase
def foo: String =
this.f
}
You can check like following.
Foo.foo
// res: String = ""
Foo.foo = "HELLO"
Foo.foo
// res: String = "hello"
Scala only recognizes this method as a setter if you have a getter def foo = ... as well:
If x is a parameterless method defined in some template, and the same template contains a setter method x_= as member, then the assignment x = e is interpreted as the invocation x_=(e) of that setter method.
From your comment:
Looks like 2.12.9 fixed it. It was broken with the version I was using 2.12.8.
Testing at https://scastie.scala-lang.org/8uAu5WCAQJa3darpMkCidg, I get the expected result: without a getter it fails in both 2.12.8 and 2.13.1, with one it works in both.
Related
Given the following String:
"println(\"Hello\")"
It is possible to use reflection to evaluate the code, as follows.
object Eval {
def apply[A](string: String): A = {
val toolbox = currentMirror.mkToolBox()
val tree = toolbox.parse(string)
toolbox.eval(tree).asInstanceOf[A]
}
}
However, lets say that the string contains an object with a function definition, such as:
"""object MyObj { def getX="X"}"""
Is there a way to use Scala reflection to compile the string, load it and run the function? What I have tried to do has not worked, if anyone has some example code it is very appreciated.
It depends on how strictly you define the acceptable input string. Should the object always be called MyObj? Should the method always be called getX? Should it always be 1 method or can it be multiple?
For the more general case you could try to extract all method names from the AST and generate calls to each one. The following code will call every method (and returns the result of the last one) that takes 0 arguments and is not a constructor, in some object, not taking inheritance into account:
def eval(string: String): Any = {
val toolbox = currentMirror.mkToolBox()
val tree = toolbox.parse(string)
//oName is the name of the object
//defs is the list of all method definitions
val ModuleDef(_,oName,Template(_,_,defs)) = tree
//only generate calls for non-constructor, zero-arg methods
val defCalls = defs.collect{
case DefDef(_,name,_,params,_,_)
if name != termNames.CONSTRUCTOR && params.flatten.isEmpty => q"$oName.$name"
}
//put the method calls after the object definition
val block = tree :: defCalls
toolbox.eval(q"..$block")
}
And using it:
scala> eval("""object MyObj { def bar() = println("bar"); def foo(a: String) = println(a); def getX = "x" }""")
bar
res60: Any = x
I'm trying to make it so I can get a value from one model into the creation of another model. This is very simplified but gives the error I'm having with a model instance extending a squeryl model. In reality I'm doing some calculations specific to this model, but need a value from another model.
I'm getting an error doing all sorts of versions of this:
class Bar(
val bazId: String
val someValue: String
) extends db.BaseModel {
val foo: Foo = db.MyDb.foos.lookup(bazId).head
def this(
bazId: Baz
) = {
this (
Baz.id,
foo.someValue,
)
}
The error is:
not found: value foo
[error] foo.someValue,
^
I've tried having some kind of lookup in the Object/singleton, inside of the def this() (that gives a "Application does not take parameters" error), and other things but nothing is working. Seems so simple, but having no luck at all.
The issue is you are trying to access a member of the class in the constructor, and since this is before the object has been constructed - it is not accessible. Doing it in the companion should help you get around that. Something like:
object Bar {
val foo(bazId:String): Foo = db.MyDb.foos.lookup(bazId).head
}
class Bar(
val bazId: String,
val someValue: String
) extends db.BaseModel {
val foo: Foo = Bar.foo(bazId)
def this(
bazId: String
) = {
this (
bazId,
Bar.foo(bazId).someValue
)
}
}
Or, if you did intend to have the constructor accept the class Baz, then you could also add the lookup method directly in Baz - then you can just call it directly to look up Foo.
I'm reading a book "Scala in action" to learn scala. On page 59, the author provide following code. But when I run it, it doesn't compile.
class Person(var firstName:String, var lastName:String, private var _age:Int) {
def age = _age
def age_ = (newAge: Int) = _age = newAge //Error
}
It reports:
<console>:3: ';' expected but '=' found.
def age_ = (newAge: Int) = _age = newAge}
This book use scala 2.10. I'm using scala 2.11.
Does scala change the usage of setter method in 2.11?
I'm not sure what the context of def age_ = (newAge: Int) = _age = newAge or what the author is trying to demonstrate with that line. Parameters of the constructor are public by default so removing private allows you to use the setter for free.
scala> class Person(var firstName:String, var lastName:String, var _age:Int) {}
defined class Person
scala> val bob = new Person("Bob", "Smith", 42)
bob: Person = Person#290d210d
scala> bob._age = 43
bob._age: Int = 43
scala> bob._age
res9: Int = 43
It looks like the only problem is the missprint ' ' ('space') simbol of the errored line between 'underscore' and 'equals'.
The right code is:
def age_= (newAge: Int) = _age = newAge //NO Error
Lets remove syntax sugar (plus abit classic formatting) and we'll have more clear method that is really the setter for "variable" age "backed" to private var _age
def age_=(newAge: Int): Unit = {
_age = newAge
}
Think about such variables as if it is virtual-like: this setter with previously defined getter but possibly with no storage at all. For instance, both uses HTTP requests (GET & PUT) to store/retrieve the value).
So, the first '=' is really the part of the method name age_= that is the syntax Scala uses to define setter for age.
I found this explanation on how to propagate overriden member values to superclass constructors by using lazy val. Unfortunately, the article does not explain why this works.
I understand than non-lazy values cannot be assigned twice and that therefore, no value is available in a super constructor since the value assignment in the super class constructor must be skiped in order to not lock the variable to another value. However, how can the println statement - which is executed in the super constructor, i.e. before the new lazy value is asigned - already know about this new value? Am I confusing something about the execution order? Or is println somehow only evaluating its argument after the object is constructed?
It's pretty simple. You just should note that all fields and lazy fields are getter methods.
val getter returns value of private[this] field. private[this] field assignment is located in primary constructor:
class Test {
val field = 1
}
means something like this:
class Test {
private[this] val _field: Int = _
def field = _field
{ // constructor
_field = 1
}
}
So before constructor field returns default value.
lazy val evaluates block of code using double check lock and than returns result:
class Test {
lazy val field = 1
}
means something like this:
class Test {
private[this] val _field: Int = _
#volatile private[this] val _flag: Boolean = _
def field = {
if (! _flag) {
synchronized {
if (! _flag) {
_field = 1 // code block
_flag = true
}
}
}
_field
}
}
So lazy val has nothing with constructor, you'll get same result before and after constructor.
You could check this using scalac -Xprint:mixin test.scala.
In my DSL I want this functionality:
class Test {
val compA = dependant(true, true)(Component("parameters"))
//and this shortcut:
val compB = dependant Component("parameters")
}
where:
def dependant(onEnable: Boolean, onDisable: Boolean)(c: Component): Component = {
//...
}
def dependant(c: Component): Component = dependant(false, true)(c)
all is fine, however, I cannot use this syntax:
val compB = dependant Component("parameters")
because it says
ambiguous reference to overloaded definition, both method dependant in
class Test of type (onEnable: Boolean, onDisable: Boolean)(c:
Component)Component and method dependant in class Test of type (c:
Component)Component match expected type ?
But if I enclose the parameter in parenthesis:
val compB = dependant(Component("parameters"))
the error is gone. Obviously, the compiler fails in desugarating the parenthesisless case. Is this expected or am I doing something wrong? If this is expected, then Why? How can I reclaim the ability to use the method dependant as a prefix, without parenthesis?
In dependant Component("parameters") you are trying to use a prefix notation to call the dependant. Scala's support for prefix notation is limited.
See Scala - Prefix Unary Operators.
An alternative is to use a postfix notation (as in Component("parameters") dependant).
If you can modify the implementaiton of Componenet, this simply means adding the dependant methods to Component:
class Component(name: String) {
def dependant: Component = //...
def dependant(onEnable: Boolean, onDisable: Boolean): Component = {
//...
}
}
class Test {
val compA = Component("parameters") dependant(true, true)
val compB = Component("parameters") dependant
}
If you can't modify Component, you can use the "pimp my library idiom".
See http://www.decodified.com/scala/2010/12/02/the-quickpimp-pattern.html for a short introduction to this idiom (along with a warning on using an anonymous class as below):
case class Component(name: String)
implicit def toPostifxDependentOps( c: Component ) = new {
def dependant: Component = dependant(false, true)
def dependant(onEnable: Boolean, onDisable: Boolean): Component = {
//...
}
}
class Test {
val compA = Component("parameters") dependant(true, true)
val compB = Component("parameters") dependant
}
Writing myObject functionName paraminstead of myObject.functionName(param) works as expected if you propvide an object. If you don't, the compiler will be lost. For example:
scala> println("Hello")
Hello
scala> println "Hello"
<console>:1: error: ';' expected but string literal found.
println "Hello"
^
A possible workaround: create an object to wrap your method:
scala> case class Component(name: String, components: Option[Component] = None)
defined class Component
scala> object depends {def on(c: Component) = Component("dependant", Some(c))}
defined module depends
scala> depends on Component("foo")
res3: Component = Component(dependant,Some(Component(foo,None)))