Consider a class:
class Whatever:
rang = 'itselop'
def __init__ (self, name):
self.name = name
self.suka = name + " " + ' musorskaya'
#classmethod
def func(cls, attr):
cls.rang = attr
No error, if this passed in. I write then Whatever.func = 'patskak', expecting that this value shoud overwrite the class variable. But the class variable remains. I thought, this is because strings are immutable; but same thing repeats, when I make 2 integers as the class variable and the class method agrument. Why?
Thank you.
Related
In Scala how are not class parameters not truly the values being called on the object? The class parameters are part of primary constructor, so should it not be setting up the member variables of the objects, like Java? Why must we make separate fields that are the values being set on the objects? Rather than just accepting the fact, is there any good explanation?
If you want to call the parameters assigned in class's primary constructor, you will have to declare them as field.
class Man(name: String, age: Int) {
def show = "My name is " + name + ", age " + age
}
Here name and age is constructor parameter. They are only accessible in the class scope.
class Man(val name: String, age: Int) {
def show = "My name is " + name + ", age " + age
}
Notice name is now a variable. So now you can access name with Man class's instance.
val x = new Man("Jack",10)
x.name // Jack
But you can not access age because it is a parameter not field.
The class parameters are part of primary constructor, so should it not be setting up the member variables of the objects, like Java?
Even in Java constructor parameters do not automatically become class members
public class User {
public User(String name, Integer age) {
// do something
}
}
User user = new User("Picard", 75);
String name = user.name // error
so we have to do something like
public class User {
String name;
Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
}
Why must we make separate fields that are the values being set on the objects?
Using case class we get that for free (along with few other things)
case class User(name: String, age: Int)
val user = User("Picard", 75)
val name = user.name // ok
In Scala how are not class parameters not truly the values being called on the object?
Indeed, in certain cases class parameters are implemented as fields with the scope set to private[this].
Here is an excerpt from the discussion in scala-lang website.
A parameter such as class Foo(x : Int) is turned into a field if it
is referenced in one or more methods
Such a field is as if it had been declared as private[this] val x: Int.
If the parameter isn't referenced in any method, it does not give
rise to a field.
Why does subclass create a copy of field when inheriting using a primary constructor?
For example
object Question
{
class Animal(var name : String) {
def setName(name : String) {
this.name = name
}
}
class Dog(name : String) extends Animal(name) {
this.setName("dog: " + name)
override def toString: String = this.name // this actually returns "Billy"
}
def main(args: Array[String]) {
val dog = new Dog("Billy")
println(dog.toString) // output "Billy", why?
println(dog.name) // output "dog: Billy", why?
}
}
As you can see, dog.toString() returns "Billy" instead of "dog: Billy", does it mean this.name is different from inherited name ? If so, then why does dog.name return "dog: Billy" ?
If you run your compiler with the -Xlint option you should see the following.
warning: private[this] value name in class Dog shadows mutable name
inherited from class Animal. Changes to name will not be visible
within class Dog - you may want to give them distinct names.
If you rename the name argument to the Dog class, the warning goes away and the output is more consistent and perhaps closer to what's expected.
Here's your code debug result
.
So, what you can see is that there are really actually two instances of variable "name". One is from "Animal", and one from "Dog". Constructors work a little bit different in Scala - what you call constructor arguments are actually local variables that are initialized with constructor arguments.
I can't really provide any elegant solution to this, unfortunately.
Also, I might be wrong. Please correct me if I am.
Update
Try this question.
Is there an elegant way in Scala to use case classes (or case classish syntax) with inheritance and default constructor parameters? I kind of want to do this (without repeating the default parameters of the superclass):
abstract class SuperClazz(id: String = "")
case class SubClazz(name: String = "", size: Int = 0) extends SuperClazz
val sub = SubClazz(id = "123", size = 2)
I would say it's not possible to do without repeating parameters from super class. It is due to the fact that case classes are special type of scala classes. It is beacuse compiler implicitly generates companion extractor object with apply and unapply methods and in those methods it will be no parameter that is not specified in class parameters.
Consider this code snippet
abstract class SuperClazz(id: String = "")
class SubClazz(name: String,id: String) extends SuperClazz {
override def toString: String = "name: " + name + ",id: " + id
}
object SubClazz {
def apply(name: String = "", id: String = "") = new SubClazz(name, id)
}
It's shorter and simpler ( and little bit different regarding toString method ) version of what is being created when
case class SubClazz(name: String, id: String) extends SubClazz
is called.
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.
I have a scala class:
class Foo {
def this(st: String) {
var baz = List[String]()
var jaz = "one" + st
// more code logic
}
}
First above code does not compile. Secondly I want baz and jaz to be private variables local to the lone constructor above and not instance variables.
How to solve this problem?
It does not compile because the first thing that MUST happen in an auxiliary constructor is a call to the primary constructor. I don't understand the second question, since the variables you have declared already ARE private
Something like this is maybe what you are looking for?
class Foo(st: String) {
val myInstance = {
var baz = List[String]()
var jaz = "one" + st
jax + baz.mkString(":")
}
}
The body of your class is the constructor. If you want to have some temporary values, you can declare a block with just about anything you want; that block can return a value, and you can store that value in an instance variable, in this case myInstance.