I understand that val keyword determines the underlying variable is a Immutable type (Cannot be reassigned later time). Now i come across a paragraph in programming in scala (Chapter 3, Next steps in scala - parameterize arrays with types), it states
val greetStrings: Array[String] = new Array[String](3)
greetStrings(0) = "Hello"
greetStrings(1) = ", "
greetStrings(2) = "world!\n"
These three lines of code illustrate
an important concept to understand
about Scala concerning the meaning of
val. When you define a variable with
val, the variable can’t be reassigned,
but the object to which it refers
could potentially still be changed. So
in this case, you couldn’t reassign
greetStrings to a different array;
greetStrings will always point to the
same Array[String] instance with which
it was initialized. But you can change
the elements of that Array[String]
over time, so the array itself is
mutable.
so its valid to change the elements of array. And its invalid if we define like this
greetStrings = Array("a","b","c")
It satisfies the below statement
When you define a variable with
val, the variable can’t be reassigned,
but the object to which it refers
could potentially still be changed.
but if i declare something like this
val str = "immutable string"
By the definition given in the book
what it means object to which it refers could potentially still be changed in the above line of code ??
Declaring a val does not guarantee or even imply an immutable type. It only declares what you might call in Java a final variable. The identifier cannot be re-assigned, but the value may be of a mutable type.
In your example of a string value, you have both a val and an immutable type, String. So this identifier is neither re-assignable nor modifiable (immutable).
Related
A literal is an object in Scala, so if you store that into a variable such as val x: Int = 5; would this make this an object as well? Everything seems like to be an object in Scala for some reason.
A literal is an object in Scala,
Well. "Literal" is a property of the source code, mostly. As such, the idea of "being an object" doesn't really apply.
What is correct is that every literal evaluates to an object.
So, the literal 1 in a source file is not really an object. It is just part of the source code. But it evaluates to an object, namely an instance of the class scala.Int that represents the mathematical idea of the integer 1.
so if you store that into a variable such as val x: Int = 5; would this make this an object as well?
What do you mean by "this"?
x is not an object, it is a variable. In Scala, like in almost every other language, variables are not objects themselves, rather they are names for objects. (Technically, a variable references an object.)
Int is not an object, either, it is a type. Types aren't objects. It is possible, however, that a type and a term have the same name, and the reason why that works is precisely because types aren't objects and thus there can never be any confusion about whether you are talking about the type or the term.
Now, 5 in this expression is an object, or more precisely, as we have seen above, it is an integer literal with evaluates to an object.
So, I am new to programming and this might be a very rookie question.
I need to add elements to an object. How is this done?
scala> case class test (
a: String,
b: String,
c: Int,
d: Int
)
var teamData_Temp = test(lol, lel,1, 2)
var teamData_All = teamData_Temp
Then let's say that teamData_Temp becomes teamData_temp = test(kok,kek,3,4) at some point in the script
How do I produce teamData_All = (test(lol,lel,1,2),test(kok,kek,3,4)) ???
Scala is a statically typed language. This means that although variables declared with var can be replaced with a new value, the type of that variable cannot change over the lifetime of the program. The type of teamData_All in your script is test while the type of teamData_All that you are trying to change it to is Tuple2[test, test] (or equivalently (test, test)). These are incompatible types.
If you want to have teamData_All be growable, you have to specify that sort of behavior upfront when declaring the variable, e.g. by making it a list of type List[test]. Then you could have one line set teamData_All = List(test(lol,lel,1,2)) and then have another line set teamData_All = List(test(lol,lel,1,2),test(kok,kek,3,4)).
The reason why this is necessary for a statically typed language is because if you make references to teamData_All in multiple places in your code, there is no way for the compiler to statically, i.e. before running your code, know what the type of teamData_All is at a given point, since you might have changed its type. This makes it impossible for the compiler to make its usual guarantees (e.g. making sure you're only calling methods on things that actually have that method defined).
How is it possible to create variable of type Any?
And why does isInstanceOf[Int] print true?
I declared x to be Any, not Int.
How does it work? What is happening behind the scenes?
val x = 4: Any // OK
x.isInstanceOf[Int] // true
x.isInstanceOf[String] // false
[EDIT] Maybe to rephrase my question:
How does val x = 4: Any look like in memory?
And once it is stored in memory as Any type, how can I later say that this particular blob of bytes is Int, but not say String?
Does it come along with some kind of information what was the "original" type? Here for example if I typed 4 AND LATER said this is Any type, would it store this original type of 4 as an Int?
Scala language is defined to support the notion of inheritance polymorphism. In other words, if there is some type T which inherits from type U, then any value of type T can be assigned to a variable of type U:
class T extends U
val x: U = new T // compiles
Same thing with Any and Int: in Scala, Int inherits from Any, therefore it is possible to store an integer in an Any variable:
val x: Any = 4 // essentially the same as your example
Also, all of the runtimes Scala runs on know what type of value is actually stored in a variable, regardless of the static type of this variable. This is important for many features of the language, in particular, virtual method overrides, but it also allows you to do manual checks and downcasts, which is what your code does (the checks). In other words, the isInstanceOf method checks the runtime type of a value stored in a variable, not the static type known at the compile time (which would be quite pointless).
Unless I've been doing it wrong. It doesn't seem like we can do things like:
var x;
x = 1;
in Scala, but rather you have to declare and assign a value to it. Are there any reasons for why this is the case?
The obvious reason is to help not leave variables uninitialized.
Note that in your declaration without initialization, you will also need to specify the type.
var x: Type;
gives the following error:
only classes can have declared but undefined members (Note that variables need to be initialized to be defined)
Actually only abstract classes can declare members without defining them. You can still get the desired behavior (variables initialized to a default value) as
var x: Type = _
If Type is a reference type, x will be null. This scenario is useful, for example, in case where a factory method completes initialization of an object after object construction.
this works:
scala> class foo[T] {
| var t: T = _
| }
defined class foo
but this doesn't:
scala> def foo[T] = {
| var t: T = _
| }
<console>:5: error: local variables must be initialized
var t: T = _
why?
(one can use:
var t: T = null.asInstanceOf[T]
)
There is a mailing list thread where Martin answered:
It corresponds to the JVM. You can omit a field initialization but not a local variable initialization. Omitting local variable initializations means that the compiler has to be able to synthesize a default value for every type. That's not so easy in the face of type parameters, specialization, and so on.
When pressed about how there is or should be any distinction between fields and locals in the matter of Scala synthesizing default values, he went on to say:
In terms of bytecodes there IS a clear difference. The JVM will initialize object fields by default and require that local variables are initialized explicitly. […] I am not sure whether we should break a useful principle of Java (locals have to be initialized before being used), or whether we should rather go the full length and introduce flow-based initialization checking as in Java. That would be the better solution, IMO, but would require significant work in terms of spec and implementation. Faced with these choices my natural instinct is to do nothing for now :-)
So if I understand correctly, the Scala compiler does not actually synthesize default values for object fields, it produces bytecode that leaves the JVM to handle this.
According to SI-4437 there was agreement from Martin on actually endorsing the null.asInstanceOf[T] pattern in the language spec, seemingly for lack of being able to feasibly support a better alternative within existing constraints.
This is defined in section 4.2 of the Scala Language Specification (my italics)
A variable definition var x: T = _ can appear only as a member of a template. It
introduces a mutable field with type T and a default initial value
This, of course, does not answer the why this should be so!
Here is at least one use case that I just uncovered. When then superclass initializes member variables via reflection it can actually initialize a subclasses member variables. However, if a subclass also initializes the member variable with a value, then this will have the effect of overwriting the value that the superclass gave it. This can be avoided by initializing the subclasses member variable with the underscore. This is why the language spec talks about giving the variable a getter function that returns the current value a little further down from the quoted sentence in oxbow_lake's sentence.