How to add instance name to String using this-keyword? - scala

I'm searching for quite a while to get around the following problem:
Every instance of my class "B" uses a method to store a Seq "output" in a file.
class B extends IO {
private var b = 0.0
var output = Seq(0.0)
def add(a:Int) = {
b += a
output :+= b
WriteToFile(fileName, output)
}
}
And theres also a trait where the WriteToFile-method is:
trait IO {
def WriteToFile(fileName:String, data:Seq[Int]) = {
create file and name it something like: fileName+this+".m"
}
}
So every time the method "add" is called on an instance on class "B", the output-sequence is stored in a file. I want to create a different file for every instance of class "B". But when I create an instance like
val x = new B
the this-keyword in the WriteToFile-Method just adds "Bank()" to the fileName. So, how can alter the code in such a way that every new instance of class "B" creates its own file? And how can I alter the WriteToFile-Method in such way that the name of the instance (here "x") is added to the String determining the fileName?

I'd discourage you from trying naming object instances according to the names of your variables. Variables are very different from references. For example, let's have this piece of code:
def foo: Object = {
val x = new Object;
val y = x;
return x;
}
This method creates some new Object. The reference to the object is assigned to variable x and then to variable y. So now we have one objects, but referenced by two variables. And when the method returns, the object still exists, but perhaps with variable referencing it.
So naming the object by a variable that's holding it isn't very meaningful - there can be multiple such variables, or none, and it changes during the lifetime of the object.
Instead, I'd suggest you to create your own mechanism for generating names. One possibility is to use an atomic counter (so that it can be safely used from multiple threads):
trait AtomicName {
val name = "prefix" + AtomicName.newId;
}
object AtomicName extends App {
import java.util.concurrent.atomic.AtomicInteger;
private val counter = new AtomicInteger(0);
protected def newId = counter.getAndIncrement;
}
Now everything extending AtomicName will have a unique name.

trait IO {
def myName =
this.getClass.getName.split("\\$",-1).dropRight(1).lastOption.getOrElse("")
}
class B extends IO {
var output = Seq(0.0)
}
object x extends B {
def test { println(myName + " has " + output) }
}
Note that you must use object x instead of val x, and this does contain some overhead, plus it is lazy--x gets created the first time its contents are used, not the first time it's stated. (If you call myName on something that is not an object, it will give you an empty string.)
I think this is a bad idea, but this is how to do it.

Related

Scala collection whose elements can construct sibling instances using named parameters and default values?

I want to have a collection of objects, each object a companion of a different class, which classes all share a common method defined in a superclass that can be invoked when looping through the collection with a foreach(). I want the constructors of these sibling-classes to have the same named parameters and default parameter values as each other. Finally, I want to minimize repeated code.
Thus far, I am trying to do this with case classes, since--if it worked--it would eliminate all the duplicated code of the companion-objects for each type. The problem is that if I put all these companion objects into a Set, when I take them out again I lose the default parameters and parameter names.
Here is some example code of what I am describing:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
case class caseOne(override val param: String = "default") extends MyType
case class caseTwo(override val param: String = "default") extends MyType
object Main extends App {
// I can construct instances using the companion objects' `apply()` method:
val works1 = caseOne(param = "I have been explicitly set").label
// I can construct instances that have the default parameter value
val works2 = caseOne().label
// But what I want to do is something like this:
val set = Set(caseOne, caseTwo)
for {
companion <- set
} {
val fail1 = companion() // Fails to compile--not enough arguments
val fail2 = companion(param = "not default") // Fails also as param has lost its name
val succeeds = companion("nameless param") // this works but not what I want
println(fail1.label + fail2.label) // this line is my goal
}
}
Notably if the Set has only one element, then it compiles, suggesting the inferred type of the multi-element Set lacks the parameter name--even though they are the same--and the default values. Also suggesting that if I gave the Set the right type parameter this could work. But what would that type be? Not MyType since that is the type of the companion classes rather that the objects in the Set.
I could define the companion objects explicitly, but that is the repeated code I want to avoid.
How can I loop through my collection, constructing instances of MyType subclasses on each iteration, with constructors that have my desired parameter names and default values? All while minimizing repeated code?
Update: Originally the example code showed caseOne and caseTwo as having different default values for param. That was incorrect; they are now the same.
You're not going to be able to get exactly what you want since you don't really have much control over the auto-generated companion objects. In particular for this to work they would all need to extend a common trait. This is why it fails to compile when the set has more than one companion object; even though they all have a method with the same signature, they don't extend a common trait for the compiler to utilize.
You can use a nested case class and get something very similar though:
trait MyType {
val param: String
def label = param // all instances of all subclasses have this method
}
abstract class MyTypeHelper(default: String) {
case class Case(param: String) extends MyType
def apply(param: String) : Case = Case(param)
def apply(): Case = apply(default)
}
object One extends MyTypeHelper("default one")
object Two extends MyTypeHelper("default two")
object Example {
val works1 = One(param = "I have been explicitly set").label
val works2 = One().label
val set = Set(One, Two)
for {
companion <- set
} {
val a = companion()
val b = companion(param = "not default")
val c = companion("nameless param")
println(a.label + b.label)
}
}
Instead of having a caseOne type, you have One.Case, but it still implements MyType so you shouldn't have any issue anywhere else in the code that uses that trait.

Is this class Immutable or mutable

Is the below Scala class is mutable or immutable?
I believe that its immutable as I can't edit the variables or access them once its created but whats making me doubt myself is the fact that it returns the current instance of a variable using its functions. It also does not have final in front of it which is further making me doubt myself.
class person(name:String, dob:String){
def getName = name
def getDob = dob
def display() = {
println("Name "+name+" dob: "+dob)
}
}
Thanks,
You have a misconception with the term Immutable:
I believe that its immutable as I can't edit the variables or access
them once its created
That's the definition of a private thing (method, variable, ...). Immutability refers to the fact that you cannot mutate state, that is, you can't change the value of something unless you create a new instance of it.
Let's see it with an example:
trait Foo{
def myMutableValue: Int
}
class Clazz extends Foo{
var myMutableValue = 1
def changeState(): Int = {
myMutableValue += 1
myMutableValue
}
}
val bar = new Clazz
bar.changeState() // myMutableValue = 2
bar.changeState() // myMutableValue = 3
bar.changeState() // myMutableValue = 4
bar.myMutableValue // myMutableValue = 4
With that example, in your instance of Clazz (bar) you're changing the state of a class attribute, in this case myMutableValue is changing its value every time I invoke changeState.
Please note that the class is public by default and changeState is also public and that doesn't means that is immutable.
Now, let's see an immutable approach:
trait Foo{
def myMutableValue: Int
}
class Clazz extends Foo{
val myMutableValue = 1
def changeState(): Int = myMutableValue + 1
}
val instance = new Clazz
instance.changeState() // myMutableValue = 2
instance.changeState() // myMutableValue = 2
instance.changeState() // myMutableValue = 2
instance.myMutableValue // 1
With this approach, every call to changeState will evaluate to 2, no matter how many times I call the function. That is, because we're dealing with an immutable value (val myMutableValue = 1). Every invocation of changeState will perform the evaluation and return a copy of that value. You're not modifying in any way the value of myMutableValue.
Please take a look to this and this.
Also, please take a look at your code, you have some errors:
By convention, class name should be capitalized (Person instead of person).
You don't need to reassign your class values with def (def getNameand def getDob). You can use class values as is.
Lastly:
It also does not have final in front of it which is further making me
doubt myself.
Again, you're talking about different things. final, as in Java, is a modifier to prevent your class to be extended. It doesn't relate in any way to immutability In adition, if you want to prevent mutability in your subclass you have to make all their members final (see this).
Since your example is coded in Scala you have all the tools that the language itself offers at your disposal (e.g. val, sealed, final)
Please note that I've used a trait to explain the possible use of def.
EDIT: about final modifier and immutability
Thanks to #Silvio Mayolo and #puhlen for the comments and clarification about final

Make a variable globally readable, but only from the file writable

I want to have a var in a singleton object that I want to read from everywhere but only write into it from another singleton object (which is a companion object, but I don't think it matters here). Thus I put both objects into one file MyClass and made the var private but opened it up to the scope of the file with private[MyClass].
As a toy example: Everything is in the same file "MyClass.scala":
object OtherObject {
private[MyClass] var myvar = 0.0
def variable = myvar
}
object MyClass{
def setmyvar(myvar: Double): Unit = {
OtherObject.myvar = 2.0
}
}
class MyClass { ... }
This does not work however. I get the error "MyClass is not an enclosing class". How can I do what I want to do?
This will be not a companion object. You can have companion of class and object, both sharing the same name. Thus the error.
Putting that aside, you can achieve that what you asked for, by having both objects in the same package and limiting access with private to that package, or wrapping those objects with another one, and setting appropriate private modifier, like here:
object MyWrapper {
object OtherObject {
private[MyWrapper] var myvar = 0.0
def variable = myvar
}
object MyClass{
def setmyvar(myvar: Double): Unit = {
OtherObject.myvar = myvar
}
}
}
And then it works:
scala> MyWrapper.OtherObject.variable
res3: Double = 0.0
scala> MyWrapper.MyClass.setmyvar(3)
scala> MyWrapper.OtherObject.variable
res5: Double = 3.0
although it isn't especially elegant piece of code
but opened it up to the scope of the file
A file doesn't define a scope in Scala, period. So you can't make something writable only within the same file.
(There are actually three cases where files are relevant to scope that I can think of:
Top-level package statements have the rest of the entire file as their scope.
A class and an object with the same name are only companions if they are in the same file.
sealed traits or classes can only be extended in the same file.
None of them are useful for your question.)
A companion object must be defined inside the same source file as the class. Both should have same name. one should be class and another should be object type. Then only we can call it as companion.
object MyClass {
private[MyClass] var myvar = 0.0
def variable = myvar
}
class MyClass{
def setmyvar(myvar: Double): Unit = {
// your logic
}
}
http://daily-scala.blogspot.in/2009/09/companion-object.html

Idiom for creating a scoped value only once in scala

Say I define a function that declares a variable in its body thus:
def foo = {
val x = new X()
x.bar
}
Is there a way I can do this such that x is only created once no matter how many times I call the function? In other words can I achieve:
val x = new X()
def foo = {
x.bar
}
but keep the definition of x within the scope of the function?
You cannot do that. If your variable is declared inside a block B. This variable cannot be seen outside B.
What you can do, is to make a class or an object to make an attribut visible outside of a definition.
object CoolObject {
val x = new X()
def foo = {
// [...]
x.bar
// [...]
}
}
If x is truly singleton, then you need to put it into a singleton context. The Scala way to do this is to create an object.
object xHolder {
val x = new X()
}
...
def foo = {
import xHolder._
x.bar
}
If foo is part of a class that has a companion object, you could put it there as well.

How to use MongoListField to return a list

I am learning lift and mongodb. I encountered a problem as following. I will bypass some code for simplicity. Here is the code:
object User extends User with MetaMegaProtoUser[User] {
}
class User extends MegaProtoUser[User] {
def meta = User
//record the post list that user like
object likePostList extends MongoListField[User, ObjectId](this)
def test()
{
val list: = this.likePostList
println(list.length)
}
}
error: value length is not a member of object User.this.likePostList
this.likePostList.length
I can store the ObjectId data in MongoDB. But the MongoListField does not return a list. Why? How to use it as a List.
I try to add type case it to List[OjbectId] or List[String] but without luck.
val list: List[ObjectId] = this.likePostList.asInstanceOf[List[Object]]
Got error:
java.lang.ClassCastException: com.cosiin.model.User$likePostList$ cannot be cast to scala.collection.immutable.List
I think I am using MongoListField the wrong way. But I do not know how to use it.
Can anyone help? Thanks
Fields you declare in Lift Records are field objects, not the actual values contained within the field. In order to access the actual value you need to call:
this.likePostList.get
or if the field is optional
this.likePostList.valueBox
which returns a scala.Option like object.
If you think of it, this makes very much sense because you're actually declaring likePostList to be an instance of MongoListField when you type:
object likePostList extends MongoListField[User, ObjectId](this)
as opposed to
val likePostList: List[ObjectId] = ...
there's no magic Scala can do to automatically convert that to List[ObjectId]. It's the same as:
class Foo {
val bar = 3
object baz { val greeting = "hello" }
}
val foo = new Foo
println(foo.bar) // prints 3
println(foo.baz) // prints something like Foo$baz$#1d981b6a
println(foo.baz.greeting) // prints "hello"
P.S. in older versions of Lift, get was called is.