How can I override "toString" to make this Scala code acts like the following Java code.
Code in Scala
object BIT extends Enumeration {
type BIT = Value
val ZERO, ONE, ANY = Value
override def toString() =
this match {
case ANY => "x "
case ZERO=> "0 "
case ONE => "1 "
}
}
val b = ONE
println(ONE) // returns ONE
Wanted toString behaviour should produce same output as the following Java code.
public enum BIT {
ZERO, ONE, ANY;
/** print BIT as 0,1, and X */
public String toString() {
switch (this) {
case ZERO:
return "0 ";
case ONE:
return "1 ";
default://ANY
return "X ";
}
}
}
BIT b = ONE;
System.out.println(b); // returns 1
I think I am overriding the wrong "toString" method.
First, yes you are overriding the wrong toString method. You're overriding the method on the BIT object itself, which is not very useful.
Second, you do this much easier by simply doing
object BIT extends Enumeration {
type BIT = Value
val ZERO = Value("0")
val ONE = Value("1")
val ANY = Value("x")
}
Then you can do
println(BIT.ONE) //prints "1"
If you want to set the value and the string you can do it like this:
scala> object BIT extends Enumeration {
| type BIT = Value
| val ZERO = Value(0, "0")
| val ONE = Value(1, "1")
| val ANY = Value("x")
| }
defined module BIT
scala> BIT.ZERO.toString
res2: String = 0
scala> BIT.ZERO.id
res3: Int = 0
scala> BIT.ANY.id
res4: Int = 2
scala> BIT.ANY.toString
res5: String = x
Related
I am new to scala. In tutorial I saw the way to define a function is
def functionName ([list of parameters]) : [return type] = {...}
But in other's code I saw following example that function did not indicate return type. Why is this?
def parseLine(line:String) = {
val fields = line.split(",")
val stationID = fields(0)
val entryType = fields(2)
val temperature = fields(3).toFloat * 0.1f * (9.0f / 5.0f) + 32.0f
(stationID, entryType, temperature)
}
If there's no return type the last expression is return value.
example,
scala> def doSomething = "i will be returned"
doSomething: String
you can see in above example though there's no return type mentioned, it will take String as return type.
Also if the method is returning based on conditions, scalac will figure itself out the return type.
scala> def doSomething = if(1 == 1) "i will be returned" else 2
doSomething: Any
scala> doSomething
res10: Any = i will be returned
Also read - Return in Scala
object sandbox {
class Numbers {
def price() : List[Int] = List(1,3,5,7)
def printIt(): Unit = {
price.foreach(x => print(x+ " ") )
}
}
trait DoubleIt extends Numbers {
override def price() : List[Int] ={
println("doubling")
super.price.map(x => x*2)
}
}
trait AddIt extends Numbers {
override def price() : List[Int] = {
println("adding")
super.price.map( x => x+2)
}
}
def main(args :Array[String]): Unit = {
val obj = new Numbers with DoubleIt with AddIt
obj.printIt()
}
}
//output :
adding
doubling
4 8 12 16
In the above code, price() method from AddIt trait executes first (from print statement).But shouldn't the value be 6 10 14 18? Why the values are doubled before adding?
The result makes sense:
printIt calls AddIt.price
AddIt.price calls DoubleIt.price, and then adds 2 to each one
DoubleIt.price calls Numbers.price, and then dubles each one, returning List(2,6,10,14)
This means that AddIt.price returns List(2+2, 6+2, 10+2, 14+2), which is indeed the printed result
The key here is understanding that indeed AddIt.price starts before DoubleIt.price, but it uses the result of DoubleIt.price to create the return value, before the addition.
Your traits are stacked in the order that you declare them:
AddIt
DoubleIt
Numbers
When you run printIt, you're doing it on an AddIt, resulting in the following call chain:
AddIt.printIt
AddIt.printIt.price //here you get to print "adding"
AddIt.price.super.price //calls DoubleIt's price
DoubleIt.price //here you get to print "doubling"
DoubleIt.super.price //calls Number's price
Numbers.price //returns List(1, 3, 5, 7)
DoubleIt.super.price.map //doubles your list input
AddIt.super.price.map //adds 2 to the result
AddIt.printIt.foreach //prints the final result
I am getting an error from a piece of code. I will only show one line of code, at least the line I believe is causing it from the error report. It is:
b = temp(temp.length-1).toInt; //temp is an ArrayBuffer[String]
the error is:
For input string: "z"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:449)
at java.lang.Integer.parseInt(Integer.java:499)
at scala.collection.immutable.StringLike$class.toInt(StringLike.scala:231)
at scala.collection.immutable.StringOps.toInt(StringOps.scala:31)
at Driver$.stringParse$1(Driver.scala:59)
at Driver$.main(Driver.scala:86)
at Driver.main(Driver.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at scala.tools.nsc.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:78)
at scala.tools.nsc.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:24)
at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:88)
at scala.tools.nsc.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:78)
at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:101)
at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:33)
at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:40)
at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:56)
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:80)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:89)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
From what I can tell, it is causing an issue with this. Since it is immutable, I know it cannot be changed. But I am not sure. I am basing this off of
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
Once I do something like my lone of code above, does it change the whole object? Temp is an ArrayBuffer[String]. So I am trying to access a string representation of a number, and convert it. But in doing so, does this change what it is and keep me from doing anything?
If you believe putting all my code will be helpful, let me know to edit it, but it is a lot and I don't want to annoy anybody. I appreciate anybody who can help me understand this!
*EDIT: MY CODE (Only here to help me figure out my error, but not necessary to look at. I just can't see where its giving me this error).
The point of my code is to parse either one of those strings at the top. It puts together and into one string and then reads the other two symbols to go with it. It parses str just fine, but it finds a problem when it reads "z" in str2, and "y" in str3. As one can see, the problem is with the second string after the and when recursing. Its also important to note that the string has to be in that form. So it can only be parsed like "(and x (and y z))", but not in any other way that makes it more convenient.
val str = "(and x y)";
val str2 = "(and x (and y z))"; //case with expression on th right side
val str3 = "(and (and x y) z)"; //case with expression ont he left side
var i = 0; //just counter used to loop through the finished parsed array to make a list
//var position = 0; //this is used for when passing it in the parser to start off at zero
var hold = new ArrayBuffer[String]();//finished array should be here
def stringParse ( exp: String, expreshHolder: ArrayBuffer[String] ): ArrayBuffer[String] = { //takes two arguments, string, arraybuffer
var b = 0; //position of where in the expression String I am currently in
var temp = expreshHolder; //holder of expressions without parens
var arrayCounter = 0;
if(temp.length == 0)
b = 0;
else {
b = temp(temp.length-1).toInt;
temp.remove(temp.length-1);
arrayCounter = temp.length;
} //this sets the position of wherever the string was read last plus removes that check from the end of the ArrayBuffer
//just counts to make sure an empty spot in the array is there to put in the strings
if(exp(b) == '(') {
b = b + 1;
while(exp(b) == ' '){b = b + 1;} //point of this is to just skip any spaces between paren and start of expression type
if(exp(b) == 'a') {
//first create the 'and', 'or', 'not' expression types to figure out
temp += exp(b).toString;
b = b+1;
temp(arrayCounter) = temp(arrayCounter) + exp(b).toString; //concatenates the second letter
b = b+1;
temp(arrayCounter) = temp(arrayCounter) + exp(b).toString; //concatenates the last letter for the expression type
//arrayCounter+=1;
//this part now takes the symbols and puts them in an array
b+=1;
while(exp(b) == ' ') {b+=1;} //just skips any spaces until it reaches the FIRST symbol
if(exp(b) == '(') {
temp += b.toString;
temp = stringParse(exp, temp);
b = temp(temp.length-1).toInt;
temp.remove(temp.length-1);
arrayCounter = temp.length-1
} else {
temp += exp(b).toString;
arrayCounter+=1; b+=1; }
while(exp(b) == ' ') {b+=1;} //just skips any spaces until it reaches the SECOND symbol
if(exp(b) == '(') {
temp += b.toString;
temp = stringParse(exp, temp);
b = temp(temp.length-1).toInt;
temp.remove(temp.length-1);
arrayCounter = temp.length-1
} else {
temp += exp(b).toString;
arrayCounter+=1;
b+=1;
}
temp;
} else { var fail = new ArrayBuffer[String]; fail +="failed"; fail;}
}
hold = stringParse(str2, ho );
for(test <- hold) println(test);
What does temp contain? Your code assumes that it contains Strings that can be converted to Ints, but it seems that you have a String "z" in there instead. That would produce the error:
scala> "z".toInt
java.lang.NumberFormatException: For input string: "z"
...
Here's a recreation of what temp might look like:
val temp = ArrayBuffer("1", "2", "z")
temp(temp.length-1).toInt //java.lang.NumberFormatException: For input string: "z"
So you need to figure out why some String "z" is getting into temp.
EDIT:
So you're adding "expressions" to temp (temp += exp(b).toString) and also adding indices (temp += b.toString). Then you're assuming that temp only holds indices (b = temp(temp.length-1).toInt). You need to decide what temp is for, and then use it exclusively for that purpose.
No, toInt doesn't change the object, it takes the object as an argument and returns an integer, leaving the object as is.
I can't understand you question because I can`t understand you code.
Let's try to simplify you code.
First of all: you have some expressions with expression type and list of operands:
scala> :paste
// Entering paste mode (ctrl-D to finish)
abstract sealed class Operand
case class IdentOperand(name: String) extends Operand { override def toString(): String = name }
case class IntOperand(i: Int) extends Operand { override def toString(): String = i.toString() }
case class ExprOperand(expr: Expression) extends Operand { override def toString(): String = expr.toString() }
case class Expression(exprType: String, operands: Seq[Operand]) {
override def toString(): String = operands.mkString("(" + exprType + " ", " ", ")")
}
// Exiting paste mode, now interpreting.
defined class Operand
defined class IdentOperand
defined class IntOperand
defined class ExprOperand
defined class Expression
scala> Expression("and", Seq(IdentOperand("x"), IdentOperand("y")))
res0: Expression = (and x y)
scala> Expression("and", Seq(IdentOperand("x"), ExprOperand(Expression("and", Seq(IdentOperand("y"), IdentOperand("z"))))))
res1: Expression = (and x (and y z))
scala> Expression("and", Seq(ExprOperand(Expression("and", Seq(IdentOperand("x"), IdentOperand("y")))), IdentOperand("z")))
res2: Expression = (and (and x y) z)
Now we have to parse strings to expressions of this type:
scala> import scala.util.parsing.combinator._
import scala.util.parsing.combinator._
scala> object ExspessionParser extends JavaTokenParsers {
| override def skipWhitespace = false;
|
| def parseExpr(e: String) = parseAll(expr, e)
|
| def expr: Parser[Expression] = "(" ~> exprType ~ operands <~ ")" ^^ { case exprType ~ operands => Expression(exprType, operands) }
| def operands: Parser[Seq[Operand]] = rep(" "~>operand)
| def exprType: Parser[String] = "and" | "not" | "or"
| def operand: Parser[Operand] = variable | exprOperand
| def exprOperand: Parser[ExprOperand] = expr ^^ (ExprOperand( _ ))
| def variable: Parser[IdentOperand] = ident ^^ (IdentOperand( _ ))
| }
defined module ExspessionParser
scala> ExspessionParser.parseExpr("(and x y)")
res3: ExspessionParser.ParseResult[Expression] = [1.10] parsed: (and x y)
scala> ExspessionParser.parseExpr("(and x (and y z))")
res4: ExspessionParser.ParseResult[Expression] = [1.18] parsed: (and x (and y z))
scala> ExspessionParser.parseExpr("(and (and x y) z)")
res5: ExspessionParser.ParseResult[Expression] = [1.18] parsed: (and (and x y) z)
And now (as far as I understand your code) we have to replace string operands (x, y, z) with integer values. Let's add these 2 methods to Expression class:
def replaceOperands(ints: Seq[Int]): Expression = replaceOperandsInner(ints)._2
private def replaceOperandsInner(ints: Seq[Int]): (Seq[Int], Expression) = {
var remainInts = ints
val replacedOperands = operands.collect{
case n: IdentOperand =>
val replacement = remainInts.head
remainInts = remainInts.tail
IntOperand(replacement)
case ExprOperand(e) =>
val (remain, replaced) = e.replaceOperandsInner(remainInts)
remainInts = remain
ExprOperand(replaced)
}
(remainInts, Expression(exprType, replacedOperands))
}
And now we can do this:
scala> ExspessionParser.parseExpr("(and (and x y) z)").get.replaceOperands(Seq(1, 2, 3))
res7: Expression = (and (and 1 2) 3)
And if you have integer values in string form, then you can just convert them first:
scala> Seq("1", "2", "3") map { _.toInt }
res8: Seq[Int] = List(1, 2, 3)
Is it possible to have angle brackets in method names , e.g. :
class Foo(ind1:Int,ind2:Int){...}
var v = new Foo(1,2)
v(1) = 3 //updates ind1
v<1> = 4 //updates ind2
The real situation is obviously more complicated than this!!I am trying to provide a convenient user interface.
This response is not meant to be taken too seriously - just a proof that this can almost be achieved using some hacks.
class Vector(values: Int*) {
val data = values.toArray
def < (i:Int) = new {
def `>_=`(x: Int) {
data(i) = x
}
def > {
println("value at "+ i +" is "+ data(i))
}
}
override def toString = data.mkString("<", ", ", ">")
}
val v = new Vector(1, 2, 3)
println(v) // prints <1, 2, 3>
v<1> = 10
println(v) // prints <1, 10, 3>
v<1> // prints: value at 1 is 10
Using this class we can have a vector that uses <> instead of () for "read" and write access.
The compiler (2.9.0.1) crashes if > returns a value. It might be a bug or a result of misusing >.
Edit: I was wrong; kassens's answer shows how to do it as you want.
It is not possible to implement a method that would be called when you write v<1> = 4 (except, maybe, if you write a compiler plugin?). However, something like this would be possible:
class Foo {
def at(i: Int) = new Assigner(i)
class Assigner(i: Int) {
def :=(v: Int) = println("assigning " + v + " at index " + i)
}
}
Then:
val f = new Foo
f at 4 := 6
With a little trickery you can actually get quite close to what you want.
object Foo {
val a:Array[Int] = new Array(100)
def <(i:Int) = new Updater(a, i)
}
class Updater(a:Array[Int], i:Int) {
def update(x:Int) {
a(i) = x
}
def >() = this
}
Foo<1>() = 123
I am not sure why Scala requires the () though. And yes, this is a bit of a hack...
I'm currently learning Scala, and just discovered the way to create custom field getters/setters. I have a simple example working:
class Thing(private val a:Int){
override def toString = "Thing[" + a + "]"
private var _value = a
def value = _value
def value_= (newVal:Int) = _value = newVal
}
On the console I can do:
scala> var t = new Thing(2)
t: dylan.code.Thing = Thing[2]
scala> t.value
res1: Int = 2
scala> t.value = 3
scala> t.value
res2: Int = 3
Now I'm trying to bring this concept to a slightly more complicated example; I'll try to whittle the code down to what's relevant:
abstract class CellExpression[Type] extends Publisher[CellUpdateEvent[Type]] with Subscriber[CellUpdateEvent[Type], CellExpression[Type]]{
protected var cachedValue: Type = recalculateValue()
protected def recalculateValue(): Type
protected def changeValue(newValue: Type):Unit = {
val oldValue = value()
if(newValue != oldValue){
cachedValue = newValue
publish(new CellUpdateEvent(this, oldValue, newValue))
}
}
def value() = cachedValue
def notify(pub: CellExpression[Type], event: CellUpdateEvent[Type]) = changeValue(recalculateValue())
}
//....
class CellVariable[Type](private val initialValue:Type) extends CellExpression[Type]{
cachedValue = initialValue
protected def recalculateValue() = { cachedValue }
override def toString = "CellVariable[" + value + "]"
def value_= (newValue:Type) = {changeValue(newValue)}
}
As far as I can tell, I've done what I need to in order to be able to treate value as a field via its getter and setter. But when I try it out in the console, I get:
scala> var i = new CellVariable(2)
i: dylan.code.CellVariable[Int] = CellVariable[2]
scala> i.value = 3
<console>:11: error: reassignment to val
i.value = 3
^
What have I done wrong, and how can I fix it?
I actually stumbled onto the solution.
The line where I declare my value function: def value() = cachedValue is the culprit.
If I remove the parentheses to make the line def value = cachedValue everything seems to work as I expected.
You cannot change values in Scala. A value is assigned once and only once. If you want to do this then you need to use variables instead of values. In other words, change the declaration from val to var.
The problem is inside one of your class definitions and may be on a line without val because I believe that if you neglect to declare a name, then Scala assumes that it is a value and therefore immutable.
Not sure what you want getters and setters for though. Scala enables you to ignore all of that Java overhead.
It is probably the line that says cachedValue = initialValue because it is not declared with var anywhere in that class. The definition in the other class is a different name because it is in a different scope. You would have to say something like class.varname to change a variable defined in another class.