How can I change mutable incremental number to be functional - scala

I have this code UniqueKeyGenerator, there is a mutable variable number to be incrementally added, because I want to make the generated value to be predictable, I wonder how can I change it to be value instead of variable
object UniqueKeyGenerator {
var number = 0
def generate(suiteClass: Class[_]): String = {
number = number + 1
suiteClass.getCanonicalName + "." + this.number
}
}
Many thanks in advance

If you're just trying to express this with a val instead of a var, you could use an Iterator.
object UniqueKeyGenerator {
val numbers = Iterator.iterate(0)(_ + 1)
def generate(suiteClass: Class[_]): String =
s"${suiteClass.getCanonicalName}.${numbers.next()}"
}
Otherwise, I'm not sure what you're asking - maybe provide some more context?
If you have all of the inputs up front, then you can write something like this:
Seq(classOf[String], classOf[Int], classOf[String]).zipWithIndex
.map({ case (suiteClass, i) => s"${suiteClass.getCanonicalName}.$i" })
// res: List(java.lang.String.0, int.1, java.lang.String.2)

Aside from an Iterator you can also use a closure, for example if the id you want to generate is not just the next natural number, but a result of a more complex expression.
val nextId = {
var id = 0
() => {
id = id + 1 // change it to something more complex if you like
id
}
}
The "id" here is still a variable, but it is not accessible from the outside. The only way you can use it is by calling nextId:
def generate(suiteClass: Class[_]): String = {
suiteClass.getCanonicalName + "." + nextId()
}

Related

Functional way to generate file names in Scala

Ok, I want to generate temp file names. So, I created a class with var tempFileName and fileNo such that it creates files like
BSirCN_0.txt
BSirCN_1.txt
BSirCN_2.txt
But, to do this I have to keep count and the way I am going it is calling next() function of the class which returns the filename in sequence (should return BSirCN_4 in the above case. Now this goes against FP as I am modifying the state i.e. the count of names in the Object. How do I do it in a functional way. One way I can think of is keeping count where the function is called and just concatenate. Any other ways?
Just return a new object:
case class FileGenerator(tempFileName: String, fileNo: Long = 0) {
lazy val currentFileName = tempFileName + "_" + fileNo
lazy val next = FileGenerator(tempFileName, fileNo + 1)
}
You can then do:
val generator = FileGenerator("BSirCN")
val first = generator.currentFileName
val next = generator.next.currentFileName
You can avoid the mutations using an Iterator (or any other kind of infinite & lazy collection).
final class TempFileNamesGenerator(prefix: String) {
private[this] val generator =
Iterator
.from(start = 0)
.map(i => s"${prefix}_${i}.txt")
def next(): String =
generator.next()
}
val generator = new TempFileNamesGenerator(prefix = "BSirCN")
generator.next() // BSirCN_0.txt
generator.next() // BSirCN_1.txt
generator.next() // BSirCN_2.txt
A similar solution to one proposed by #Luis but using streams:
def namesStream(prefix: String, suffix: String): Stream[String] = Stream.from(0).map(n => s"$prefix$n$suffix")
Then use it like this:
val stream = namesStream("BSirCN_", ".txt")
stream.take(5) // BSirCN_1.txt, BSirCN_2.txt, BSirCN_3.txt, BSirCN_4.txt, BSirCN_5.txt
// or
stream.drop(10).take(2) // BSirCN_11.txt, BSirCN_12.txt

how do I increment an integer variable I passed into a function in Scala?

I declared a variable outside the function like this:
var s: Int = 0
passed it such as this:
def function(s: Int): Boolean={
s += 1
return true
}
but the error lines wont go away under the "s +=" for the life of me. I tried everything. I am new to Scala btw.
First of all, I will repeat my words of caution: solution below is both obscure and inefficient, if it possible try to stick with values.
implicit class MutableInt(var value: Int) {
def inc() = { value+=1 }
}
def function(s: MutableInt): Boolean={
s.inc() // parentheses here to denote that method has side effects
return true
}
And here is code in action:
scala> val x: MutableInt = 0
x: MutableInt = MutableInt#44e70ff
scala> function(x)
res0: Boolean = true
scala> x.value
res1: Int = 1
If you just want continuously increasing integers, you can use a Stream.
val numberStream = Stream.iterate(0)(_ + 1).iterator
That creates an iterator over a never-ending stream of number, starting at zero. Then, to get the next number, call
val number: Int = numberStream.next
I have also just started using Scala this was my work around.
var s: Int = 0
def function(s: Int): Boolean={
var newS = s
newS = newS + 1
s = newS
return true
}
From What i read you are not passing the same "s" into your function as is in the rest of the code. I am sure there is a even better way but this is working for me.
You don't.
A var is a name that refers to a reference which might be changed. When you call a function, you pass the reference itself, and a new name gets bound to it.
So, to change what reference the name points to, you need a reference to whatever contains the name. If it is an object, that's easy enough. If it is a local variable, then it is not possible.
See also call by reference, though I don't think this question is a true duplicate.
If you just want to increment a variable starting with 3
val nextId = { var i = 3; () => { i += 1; i } }
then invoke it:
nextId()

How is this type miss match?

HI I am new at Scala Trying to run this code:
class Number(x : Int){
var number = x
def inc(): Int = {
number => number + 1
}
}
But I get the following error: solution.scala:12: error: missing parameter type
number => number + 1
I dont know how to fix this.
Essentially, you can expicitly say what type you're expect:
def inc(): Int = {
number: Int => number + 1
}
BUT this won't compile, cause what you've defined is function, so:
def inc(): (Int) => Int = {
// some function that takes Int, calls it `number` and increment
number: Int => number + 1
}
would be closer,
BUT
it doesn't make sense and notice, that number you've defined has nothing in common with number variable inside class
-- that's why Scala compiler cannot infer type for you.
I think you have wanted to write something like:
def inc(): Int = {number += 1; number;}
// will take effect on number field
or
def inc(num: Int): Int = num + 1
or simply:
def inc = (x: Int) => x + 1
since Int return type is inferred, no need to specify it
As for dealing with mutability in the question, inc(1), inc(5), etc. are themselves transformed representations of the number passed to the class instance (i.e. they equate to "var number", but immutably so). No real need for mutability based on what we see here...

Scala Properties Question

I'm still learning Scala, but one thing I thought was interesting is that Scala blurs the line between methods and fields. For instance, I can build a class like this...
class MutableNumber(var value: Int)
The key here is that the var in the constructor-argument automatically allows me to use the 'value' field like a getter/setter in java.
// use number...
val num = new MutableNumber(5)
num.value = 6
println(num.value)
If I want to add constraints, I can do so by switching to using methods in place of the instance-fields:
// require all mutable numbers to be >= 0
class MutableNumber(private var _value: Int) {
require(_value >= 0)
def value: Int = _value
def value_=(other: Int) {
require(other >=0)
_value = other
}
}
The client side code doesn't break since the API doesn't change:
// use number...
val num = new MutableNumber(5)
num.value = 6
println(num.value)
My hang-up is with the named-parameter feature that was added to Scala-2.8. If I use named-parameters, my API does change and it does break the api.
val num = new MutableNumber(value=5) // old API
val num = new MutableNumber(_value=5) // new API
num.value = 6
println(num.value)
Is there any elegant solution to this? How should I design my MutableNumber class so that I can add constraints later on without breaking the API?
Thanks!
You can use the same trick that case classes do: use a companion object.
object Example {
class MutableNumber private (private var _value: Int) {
require (_value >= 0)
def value: Int = _value
def value_=(i: Int) { require (i>=0); _value = i }
override def toString = "mutable " + _value
}
object MutableNumber {
def apply(value: Int = 0) = new MutableNumber(value)
}
}
And here it is working (and demonstrating that, as constructed, you must use the object for creations, since the constructor is marked private):
scala> new Example.MutableNumber(5)
<console>:10: error: constructor MutableNumber cannot be accessed in object $iw
new Example.MutableNumber(5)
^
scala> Example.MutableNumber(value = 2)
res0: Example.MutableNumber = mutable 2
scala> Example.MutableNumber()
res1: Example.MutableNumber = mutable 0
Thanks for the answer! As an aside, I think the Scala-guys might be aware that there's an issue:
What's New in Scala 2.8: Named and Default Parameters
...
Until now, the names of arguments were a somewhat arbitrary choice for library developers, and weren't considered an important part of the API. This has suddenly changed, so that a method call to mkString(sep = " ") will fail to compile if the argument sep were renamed to separator in a later version.
Scala 2.9 implements a neat solution to this problem, but while we're waiting for that, be cautious about referring to arguments by name if their names may change in the future.
http://www.artima.com/scalazine/articles/named_and_default_parameters_in_scala.html
class MutableNumber {
private var _value = 0 //needs to be initialized
def value: Int = _value
def value_=(other: Int) {
require(other >=0) //this requirement was two times there
_value = other
}
}
you can modify all members of any class within curly braces
val n = new MutableNumber{value = 17}

initialise a var in scala

I have a class where I like to initialize my var by reading a configfile, which produces intermediate objects/vals, which I would like to group and hide in a method.
Here is the bare minimum of the problem - I call the ctor with a param i, in reality a File to parse, and the init-method generates the String s, in reality more complicated than here, with a lot of intermediate objects being created:
class Foo (val i: Int) {
var s : String;
def init () {
s = "" + i
}
init ()
}
This will produce the error: class Foo needs to be abstract, since variable s is not defined. In this example it is easy to solve by setting the String to "": var s = "";, but in reality the object is more complex than String, without an apropriate Null-implementation.
I know, I can use an Option, which works for more complicated things than String too:
var s : Option [String] = None
def init () {
s = Some ("" + i)
}
or I can dispense with my methodcall. Using an Option will force me to write Some over and over again, without much benefit, since there is no need for a None else than to initialize it that way I thought I could.
Is there another way to achieve my goal?
var s : Whatever = _ will initialize s to the default value for Whatever (null for reference types, 0 for numbers, false for bools etc.)
Instead of creating separate methods for initialization, you should perform the initialization using the following way :
class Foo(val i: Int) {
var s: String = {
var s0 = " "
s0 += i
// do some more stuff with s0
s0
}
var dashedDate = {
val dashed = new SimpleDateFormat("yy-MM-dd")
dashed.format(updated)
}
// Initializing more than one field:
var (x, y, z) = {
var x0, y0, z0 = 0
// some calculations
(x0, y0, z0)
}
}
Honestly, why are you using var? Why not just do:
val rootObject = readFile(filename)
This would make the most sense to me.